// Code generated by ogen, DO NOT EDIT. package api import ( "context" "net/http" "time" "github.com/go-faster/errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" ht "github.com/ogen-go/ogen/http" "github.com/ogen-go/ogen/middleware" "github.com/ogen-go/ogen/ogenerrors" ) type codeRecorder struct { http.ResponseWriter status int } func (c *codeRecorder) WriteHeader(status int) { c.status = status c.ResponseWriter.WriteHeader(status) } // handleAPIV2BufferGoodsTaskGetRequest handles GET /api/v2/buffer/goods/task operation. // // Метод предоставляет информацию о товарах и ошибках в // товарах из загрузки в обработке. //
// Необработанная загрузка — это загрузка скидок для календаря акций. Такие // скидки применятся к товарам только в момент начала // акции. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/buffer/goods/task func (s *Server) handleAPIV2BufferGoodsTaskGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/buffer/goods/task"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2BufferGoodsTaskGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2BufferGoodsTaskGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2BufferGoodsTaskGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2BufferGoodsTaskGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2BufferGoodsTaskGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2BufferGoodsTaskGetOperation, OperationSummary: "Детализация необработанной загрузки", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, { Name: "uploadID", In: "query", }: params.UploadID, }, Raw: r, } type ( Request = struct{} Params = APIV2BufferGoodsTaskGetParams Response = APIV2BufferGoodsTaskGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2BufferGoodsTaskGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2BufferGoodsTaskGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2BufferGoodsTaskGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2BufferGoodsTaskGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2BufferTasksGetRequest handles GET /api/v2/buffer/tasks operation. // // Метод предоставляет информацию про загрузку скидок в // обработке. //
// Необработанная загрузка — это загрузка скидок для календаря акций. Такие // скидки применятся к товарам только в момент начала // акции. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/buffer/tasks func (s *Server) handleAPIV2BufferTasksGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/buffer/tasks"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2BufferTasksGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2BufferTasksGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2BufferTasksGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2BufferTasksGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2BufferTasksGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2BufferTasksGetOperation, OperationSummary: "Состояние необработанной загрузки", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "uploadID", In: "query", }: params.UploadID, }, Raw: r, } type ( Request = struct{} Params = APIV2BufferTasksGetParams Response = APIV2BufferTasksGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2BufferTasksGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2BufferTasksGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2BufferTasksGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2BufferTasksGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2HistoryGoodsTaskGetRequest handles GET /api/v2/history/goods/task operation. // // Метод предоставляет информацию о товарах и об // ошибках в товарах в обработанной загрузке. //
// Обработанная загрузка — это загрузка цен и скидок // для товаров и размеров товаров, а также скидок WB Клуба. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/history/goods/task func (s *Server) handleAPIV2HistoryGoodsTaskGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/history/goods/task"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2HistoryGoodsTaskGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2HistoryGoodsTaskGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2HistoryGoodsTaskGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2HistoryGoodsTaskGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2HistoryGoodsTaskGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2HistoryGoodsTaskGetOperation, OperationSummary: "Детализация обработанной загрузки", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, { Name: "uploadID", In: "query", }: params.UploadID, }, Raw: r, } type ( Request = struct{} Params = APIV2HistoryGoodsTaskGetParams Response = APIV2HistoryGoodsTaskGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2HistoryGoodsTaskGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2HistoryGoodsTaskGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2HistoryGoodsTaskGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2HistoryGoodsTaskGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2HistoryTasksGetRequest handles GET /api/v2/history/tasks operation. // // Метод предоставляет информацию об обработанной // загрузке цен и скидок. //
// Обработанная загрузка — это загрузка цен и скидок // для товаров и размеров товаров, а также скидок WB Клуба. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/history/tasks func (s *Server) handleAPIV2HistoryTasksGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/history/tasks"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2HistoryTasksGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2HistoryTasksGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2HistoryTasksGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2HistoryTasksGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2HistoryTasksGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2HistoryTasksGetOperation, OperationSummary: "Состояние обработанной загрузки", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "uploadID", In: "query", }: params.UploadID, }, Raw: r, } type ( Request = struct{} Params = APIV2HistoryTasksGetParams Response = APIV2HistoryTasksGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2HistoryTasksGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2HistoryTasksGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2HistoryTasksGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2HistoryTasksGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2ListGoodsFilterGetRequest handles GET /api/v2/list/goods/filter operation. // // Метод предоставляет информацию о товарах по их // артикулам: цены, валюту, общие скидки и скидки для [WB // Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post). //

// Чтобы получить информацию обо всех товарах продавца, // оставьте артикул пустым, установите `limit=1000`, в // параметре `offset` установите смещение по количеству // записей. Количество нужно рассчитать по формуле: `offset` // плюс `limit` из предыдущего запроса. Повторяйте запрос, // пока вы не получите ответ с пустым массивом.
Чтобы // получить информацию о размерах товара, используйте // [отдельный // метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get). //
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/list/goods/filter func (s *Server) handleAPIV2ListGoodsFilterGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/list/goods/filter"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2ListGoodsFilterGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2ListGoodsFilterGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2ListGoodsFilterGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2ListGoodsFilterGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2ListGoodsFilterGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2ListGoodsFilterGetOperation, OperationSummary: "Получить товары с ценами", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, { Name: "filterNmID", In: "query", }: params.FilterNmID, }, Raw: r, } type ( Request = struct{} Params = APIV2ListGoodsFilterGetParams Response = APIV2ListGoodsFilterGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2ListGoodsFilterGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2ListGoodsFilterGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2ListGoodsFilterGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2ListGoodsFilterGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2ListGoodsSizeNmGetRequest handles GET /api/v2/list/goods/size/nm operation. // // Метод предоставляет информацию обо всех размерах // одного товарам: цены, валюту, общие скидки и скидки // для [WB // Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post). //

// Работает только для товаров из категорий, где можно // устанавливать цены отдельно для разных размеров. Для // таких товаров `editableSizePrice: true`. //

// Чтобы получить информацию о самом товаре, // используйте [отдельный // метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1filter/get). //
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/list/goods/size/nm func (s *Server) handleAPIV2ListGoodsSizeNmGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/list/goods/size/nm"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2ListGoodsSizeNmGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2ListGoodsSizeNmGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2ListGoodsSizeNmGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2ListGoodsSizeNmGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2ListGoodsSizeNmGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2ListGoodsSizeNmGetOperation, OperationSummary: "Получить размеры товара с ценами", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, { Name: "nmID", In: "query", }: params.NmID, }, Raw: r, } type ( Request = struct{} Params = APIV2ListGoodsSizeNmGetParams Response = APIV2ListGoodsSizeNmGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2ListGoodsSizeNmGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2ListGoodsSizeNmGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2ListGoodsSizeNmGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2ListGoodsSizeNmGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2QuarantineGoodsGetRequest handles GET /api/v2/quarantine/goods operation. // // Метод предоставляет информацию о товарах в карантине. //

// Если новая цена товара со скидкой будет минимум в 3 // раза меньше старой, товар попадёт [в // карантин](https://seller.wildberries.ru/discount-and-prices/quarantine) и будет // продаваться по старой цене. Ошибка об этом будет в // ответах методов [состояний // загрузок](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get). //

// Вы можете изменить цену или скидку с помощью API либо // вывести товар из карантина [в личном // кабинете](https://seller.wildberries.ru/discount-and-prices/quarantine). //

// Для товаров с [поразмерной установкой // цен](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post) // карантин не применяется. //
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // GET /api/v2/quarantine/goods func (s *Server) handleAPIV2QuarantineGoodsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v2/quarantine/goods"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2QuarantineGoodsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2QuarantineGoodsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2QuarantineGoodsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV2QuarantineGoodsGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV2QuarantineGoodsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2QuarantineGoodsGetOperation, OperationSummary: "Получить товары в карантине", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, }, Raw: r, } type ( Request = struct{} Params = APIV2QuarantineGoodsGetParams Response = APIV2QuarantineGoodsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV2QuarantineGoodsGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2QuarantineGoodsGet(ctx, params) return response, err }, ) } else { response, err = s.h.APIV2QuarantineGoodsGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2QuarantineGoodsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2UploadTaskClubDiscountPostRequest handles POST /api/v2/upload/task/club-discount operation. // // Устанавливает скидки для товаров в рамках подписки [WB // Клуб](https://seller.wildberries.ru/help-center/article/A-337). //
// Получить информацию о процессе установки цен и // скидок можно с помощью методов состояния и детализации обработанной загрузки. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // POST /api/v2/upload/task/club-discount func (s *Server) handleAPIV2UploadTaskClubDiscountPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/api/v2/upload/task/club-discount"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2UploadTaskClubDiscountPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2UploadTaskClubDiscountPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2UploadTaskClubDiscountPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeAPIV2UploadTaskClubDiscountPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV2UploadTaskClubDiscountPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2UploadTaskClubDiscountPostOperation, OperationSummary: "Установить скидки WB Клуба", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *APIV2UploadTaskClubDiscountPostReq Params = struct{} Response = APIV2UploadTaskClubDiscountPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2UploadTaskClubDiscountPost(ctx, request) return response, err }, ) } else { response, err = s.h.APIV2UploadTaskClubDiscountPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2UploadTaskClubDiscountPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2UploadTaskPostRequest handles POST /api/v2/upload/task operation. // // Метод устанавливает цены и скидки для товаров. //

// Чтобы установить цены и скидки для размеров товара, // используйте [отдельный // метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post). //
// Получить информацию о процессе установки цен и // скидок можно с помощью методов состояния и детализации обработанной загрузки. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // POST /api/v2/upload/task func (s *Server) handleAPIV2UploadTaskPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/api/v2/upload/task"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2UploadTaskPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2UploadTaskPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2UploadTaskPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeAPIV2UploadTaskPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV2UploadTaskPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2UploadTaskPostOperation, OperationSummary: "Установить цены и скидки", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *APIV2UploadTaskPostReq Params = struct{} Response = APIV2UploadTaskPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2UploadTaskPost(ctx, request) return response, err }, ) } else { response, err = s.h.APIV2UploadTaskPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2UploadTaskPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV2UploadTaskSizePostRequest handles POST /api/v2/upload/task/size operation. // // Метод устанавливает цены отдельно для размеров // товаров. // Работает только для товаров из категорий, где можно // устанавливать цены отдельно для разных размеров. Для // [таких // товаров](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get) `editableSizePrice: true`. // Чтобы установить цены и скидки для самих товаров, // используйте [отдельный // метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post). //
// Получить информацию о процессе установки цен и // скидок можно с помощью методов состояния и детализации обработанной загрузки. //
//
// Максимум 10 запросов за 6 секунд для всех // методов категории Цены и скидки // на один аккаунт продавца //
. // // POST /api/v2/upload/task/size func (s *Server) handleAPIV2UploadTaskSizePostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/api/v2/upload/task/size"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV2UploadTaskSizePostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV2UploadTaskSizePostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV2UploadTaskSizePostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeAPIV2UploadTaskSizePostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV2UploadTaskSizePostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV2UploadTaskSizePostOperation, OperationSummary: "Установить цены для размеров", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *APIV2UploadTaskSizePostReq Params = struct{} Response = APIV2UploadTaskSizePostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV2UploadTaskSizePost(ctx, request) return response, err }, ) } else { response, err = s.h.APIV2UploadTaskSizePost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV2UploadTaskSizePostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3OfficesGetRequest handles GET /api/v3/offices operation. // // Метод предоставляет список всех складов WB для // привязки к складам продавца. Предназначен для // определения складов WB, чтобы сдавать готовые заказы // по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller). //
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // GET /api/v3/offices func (s *Server) handleAPIV3OfficesGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v3/offices"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3OfficesGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3OfficesGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3OfficesGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } var response APIV3OfficesGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3OfficesGetOperation, OperationSummary: "Получить список складов WB", OperationID: "", Body: nil, Params: middleware.Parameters{}, Raw: r, } type ( Request = struct{} Params = struct{} Response = APIV3OfficesGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3OfficesGet(ctx) return response, err }, ) } else { response, err = s.h.APIV3OfficesGet(ctx) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3OfficesGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3StocksWarehouseIdDeleteRequest handles DELETE /api/v3/stocks/{warehouseId} operation. // // Метод удаляет запись об остатках товаров продавца из // [списка // остатков](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). //
// Действие необратимо. Удаленный остаток // будет необходимо загрузить повторно для // возобновления продаж. //
//
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // DELETE /api/v3/stocks/{warehouseId} func (s *Server) handleAPIV3StocksWarehouseIdDeleteRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("DELETE"), semconv.HTTPRouteKey.String("/api/v3/stocks/{warehouseId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3StocksWarehouseIdDeleteOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3StocksWarehouseIdDeleteOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3StocksWarehouseIdDeleteOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV3StocksWarehouseIdDeleteParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeAPIV3StocksWarehouseIdDeleteRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV3StocksWarehouseIdDeleteRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3StocksWarehouseIdDeleteOperation, OperationSummary: "Удалить остатки товаров", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "warehouseId", In: "path", }: params.WarehouseId, }, Raw: r, } type ( Request = *APIV3StocksWarehouseIdDeleteReq Params = APIV3StocksWarehouseIdDeleteParams Response = APIV3StocksWarehouseIdDeleteRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV3StocksWarehouseIdDeleteParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3StocksWarehouseIdDelete(ctx, request, params) return response, err }, ) } else { response, err = s.h.APIV3StocksWarehouseIdDelete(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3StocksWarehouseIdDeleteResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3StocksWarehouseIdPostRequest handles POST /api/v3/stocks/{warehouseId} operation. // // Метод предоставляет данные об остатках товаров на // [складах продавца](/openapi/work-with-products#tag/Sklady-prodavca). //
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // POST /api/v3/stocks/{warehouseId} func (s *Server) handleAPIV3StocksWarehouseIdPostRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/api/v3/stocks/{warehouseId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3StocksWarehouseIdPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3StocksWarehouseIdPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3StocksWarehouseIdPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV3StocksWarehouseIdPostParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeAPIV3StocksWarehouseIdPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV3StocksWarehouseIdPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3StocksWarehouseIdPostOperation, OperationSummary: "Получить остатки товаров", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "warehouseId", In: "path", }: params.WarehouseId, }, Raw: r, } type ( Request = *APIV3StocksWarehouseIdPostReq Params = APIV3StocksWarehouseIdPostParams Response = APIV3StocksWarehouseIdPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV3StocksWarehouseIdPostParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3StocksWarehouseIdPost(ctx, request, params) return response, err }, ) } else { response, err = s.h.APIV3StocksWarehouseIdPost(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3StocksWarehouseIdPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3StocksWarehouseIdPutRequest handles PUT /api/v3/stocks/{warehouseId} operation. // // Метод обновляет количество остатков товаров // продавца [в // списке](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). //
// Названия параметров запроса не валидируются. При // отправке некорректных названий вы получите успешный // ответ (204), но остатки не обновятся. //
//
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // PUT /api/v3/stocks/{warehouseId} func (s *Server) handleAPIV3StocksWarehouseIdPutRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("PUT"), semconv.HTTPRouteKey.String("/api/v3/stocks/{warehouseId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3StocksWarehouseIdPutOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3StocksWarehouseIdPutOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3StocksWarehouseIdPutOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV3StocksWarehouseIdPutParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeAPIV3StocksWarehouseIdPutRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV3StocksWarehouseIdPutRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3StocksWarehouseIdPutOperation, OperationSummary: "Обновить остатки товаров", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "warehouseId", In: "path", }: params.WarehouseId, }, Raw: r, } type ( Request = OptAPIV3StocksWarehouseIdPutReq Params = APIV3StocksWarehouseIdPutParams Response = APIV3StocksWarehouseIdPutRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV3StocksWarehouseIdPutParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3StocksWarehouseIdPut(ctx, request, params) return response, err }, ) } else { response, err = s.h.APIV3StocksWarehouseIdPut(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3StocksWarehouseIdPutResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3WarehousesGetRequest handles GET /api/v3/warehouses operation. // // Метод предоставляет список всех складов продавца. // Может использоваться для получения [остатков // товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). //
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // GET /api/v3/warehouses func (s *Server) handleAPIV3WarehousesGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/api/v3/warehouses"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3WarehousesGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3WarehousesGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3WarehousesGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } var response APIV3WarehousesGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3WarehousesGetOperation, OperationSummary: "Получить список складов продавца", OperationID: "", Body: nil, Params: middleware.Parameters{}, Raw: r, } type ( Request = struct{} Params = struct{} Response = APIV3WarehousesGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3WarehousesGet(ctx) return response, err }, ) } else { response, err = s.h.APIV3WarehousesGet(ctx) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3WarehousesGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3WarehousesPostRequest handles POST /api/v3/warehouses operation. // // Метод создаёт склад продавца для работы с [остатками // товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). Нужно привязать к складу продавца [склад WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) для работы по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller). //
// Нельзя привязывать склад WB, который уже используется //
//
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // POST /api/v3/warehouses func (s *Server) handleAPIV3WarehousesPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/api/v3/warehouses"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3WarehousesPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3WarehousesPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3WarehousesPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeAPIV3WarehousesPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV3WarehousesPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3WarehousesPostOperation, OperationSummary: "Создать склад продавца", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *APIV3WarehousesPostReq Params = struct{} Response = APIV3WarehousesPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3WarehousesPost(ctx, request) return response, err }, ) } else { response, err = s.h.APIV3WarehousesPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3WarehousesPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3WarehousesWarehouseIdDeleteRequest handles DELETE /api/v3/warehouses/{warehouseId} operation. // // Метод удаляет склад продавца из [списка // складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get). //
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // DELETE /api/v3/warehouses/{warehouseId} func (s *Server) handleAPIV3WarehousesWarehouseIdDeleteRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("DELETE"), semconv.HTTPRouteKey.String("/api/v3/warehouses/{warehouseId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3WarehousesWarehouseIdDeleteOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3WarehousesWarehouseIdDeleteOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3WarehousesWarehouseIdDeleteOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV3WarehousesWarehouseIdDeleteParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response APIV3WarehousesWarehouseIdDeleteRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3WarehousesWarehouseIdDeleteOperation, OperationSummary: "Удалить склад продавца", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "warehouseId", In: "path", }: params.WarehouseId, }, Raw: r, } type ( Request = struct{} Params = APIV3WarehousesWarehouseIdDeleteParams Response = APIV3WarehousesWarehouseIdDeleteRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV3WarehousesWarehouseIdDeleteParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3WarehousesWarehouseIdDelete(ctx, params) return response, err }, ) } else { response, err = s.h.APIV3WarehousesWarehouseIdDelete(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3WarehousesWarehouseIdDeleteResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleAPIV3WarehousesWarehouseIdPutRequest handles PUT /api/v3/warehouses/{warehouseId} operation. // // Метод обновляет данные склада продавца в [списке // складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get). // Данные о привязанном [складе // WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) можно // изменить один раз в сутки. //
// Нельзя привязывать склад WB, который уже используется //
//
// Максимум 300 запросов в минуту для всех // методов категории Маркетплейс на // один аккаунт продавца. //

// Один запрос с кодом ответа 409 учитывается как 5 // запросов //
. // // PUT /api/v3/warehouses/{warehouseId} func (s *Server) handleAPIV3WarehousesWarehouseIdPutRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("PUT"), semconv.HTTPRouteKey.String("/api/v3/warehouses/{warehouseId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), APIV3WarehousesWarehouseIdPutOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: APIV3WarehousesWarehouseIdPutOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, APIV3WarehousesWarehouseIdPutOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeAPIV3WarehousesWarehouseIdPutParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeAPIV3WarehousesWarehouseIdPutRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response APIV3WarehousesWarehouseIdPutRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: APIV3WarehousesWarehouseIdPutOperation, OperationSummary: "Обновить склад продавца", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "warehouseId", In: "path", }: params.WarehouseId, }, Raw: r, } type ( Request = *APIV3WarehousesWarehouseIdPutReq Params = APIV3WarehousesWarehouseIdPutParams Response = APIV3WarehousesWarehouseIdPutRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackAPIV3WarehousesWarehouseIdPutParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.APIV3WarehousesWarehouseIdPut(ctx, request, params) return response, err }, ) } else { response, err = s.h.APIV3WarehousesWarehouseIdPut(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeAPIV3WarehousesWarehouseIdPutResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2BarcodesPostRequest handles POST /content/v2/barcodes operation. // // Метод генерирует массив уникальных баркодов для // создания размера в [карточке // товара](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post). Можно использовать, если у вас нет собственных баркодов. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/barcodes func (s *Server) handleContentV2BarcodesPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/barcodes"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2BarcodesPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2BarcodesPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2BarcodesPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2BarcodesPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2BarcodesPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2BarcodesPostOperation, OperationSummary: "Генерация баркодов", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *ContentV2BarcodesPostReq Params = struct{} Response = ContentV2BarcodesPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2BarcodesPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2BarcodesPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2BarcodesPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsDeleteTrashPostRequest handles POST /content/v2/cards/delete/trash operation. // // Метод переносит [карточки товаров в // корзину](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). При этом карточки товаров не удаляются, их можно [восстановить](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1recover/post). //
// После переноса в корзину карточке товара // присваивается новый imtID. //
// Карточки товаров удаляются автоматически, если лежат // в корзине больше 30 дней. Очистка корзины происходит // каждую ночь по московскому времени.
// Карточки товаров можно удалить в любое время в // [личном кабинете](https://seller.wildberries.ru/new-goods/basket-cards). //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/cards/delete/trash func (s *Server) handleContentV2CardsDeleteTrashPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/cards/delete/trash"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsDeleteTrashPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsDeleteTrashPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsDeleteTrashPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2CardsDeleteTrashPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2CardsDeleteTrashPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsDeleteTrashPostOperation, OperationSummary: "Перенос карточек товаров в корзину", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *ContentV2CardsDeleteTrashPostReq Params = struct{} Response = ContentV2CardsDeleteTrashPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsDeleteTrashPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2CardsDeleteTrashPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsDeleteTrashPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsErrorListGetRequest handles GET /content/v2/cards/error/list operation. // // Метод предоставляет список карточек товаров, при // создании или редактировании которых произошли // ошибки, с описанием этих ошибок. //
// Чтобы убрать карточку товара из списка, нужно // повторно сделать запрос на создание или редактирование карточки товара с исправленными ошибками. //
//
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/cards/error/list func (s *Server) handleContentV2CardsErrorListGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/cards/error/list"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsErrorListGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsErrorListGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsErrorListGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2CardsErrorListGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2CardsErrorListGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsErrorListGetOperation, OperationSummary: "Список несозданных карточек товаров с ошибками", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2CardsErrorListGetParams Response = ContentV2CardsErrorListGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2CardsErrorListGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsErrorListGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2CardsErrorListGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsErrorListGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsLimitsGetRequest handles GET /content/v2/cards/limits operation. // // Возвращает бесплатные и платные лимиты продавца на // [создание карточек // товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post).

// Формула для получения количества карточек, которые // можно создать: // > (`freeLimits` + `paidLimits`) - количество созданных карточек // Созданными считаются карточки, которые можно // получить через методы [список карточек // товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/cards/limits func (s *Server) handleContentV2CardsLimitsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/cards/limits"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsLimitsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsLimitsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsLimitsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } var response ContentV2CardsLimitsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsLimitsGetOperation, OperationSummary: "Лимиты карточек товаров", OperationID: "", Body: nil, Params: middleware.Parameters{}, Raw: r, } type ( Request = struct{} Params = struct{} Response = ContentV2CardsLimitsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsLimitsGet(ctx) return response, err }, ) } else { response, err = s.h.ContentV2CardsLimitsGet(ctx) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsLimitsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsRecoverPostRequest handles POST /content/v2/cards/recover operation. // // Метод восстанавливает [карточки товаров из // корзины](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). //
// Карточка товара сохраняет тот же imtID, что был // присвоен ей при перемещении в корзину. //
//
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/cards/recover func (s *Server) handleContentV2CardsRecoverPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/cards/recover"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsRecoverPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsRecoverPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsRecoverPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2CardsRecoverPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2CardsRecoverPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsRecoverPostOperation, OperationSummary: "Восстановление карточек товаров из корзины", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *ContentV2CardsRecoverPostReq Params = struct{} Response = ContentV2CardsRecoverPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsRecoverPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2CardsRecoverPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsRecoverPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsUpdatePostRequest handles POST /content/v2/cards/update operation. // // Метод обновляет карточки товаров. Данные для // обновления можно получить через [список карточек // товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). //
// Карточка товара перезаписывается при обновлении. // Поэтому в запросе нужно передать все // параметры карточки, в том числе те, которые вы не // собираетесь обновлять. //
// Нельзя редактировать или удалять баркоды, но можно // добавить дополнительный баркод к карточке товара. // Параметры `photos`, `video` и `tags` редактировать или удалять // через данный метод нельзя.
// Габариты товаров можно указать только в `сантиметрах`, // // вес товара с упаковкой — в `килограммах`. // //

// В одном запросе можно отредактировать максимум 3000 // карточек товаров (`nmID`). Максимальный размер запроса 10 // Мб.
// Если ответ `Успешно` (`200`), но какие-то карточки не // обновились, получите [список несозданных карточек // товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get). //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня для метода будет отдельный // лимит — 10 запросов в минуту на один аккаунт продавца //
. // // POST /content/v2/cards/update func (s *Server) handleContentV2CardsUpdatePostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/cards/update"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsUpdatePostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsUpdatePostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsUpdatePostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2CardsUpdatePostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2CardsUpdatePostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsUpdatePostOperation, OperationSummary: "Редактирование карточек товаров", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = []ContentV2CardsUpdatePostReqItem Params = struct{} Response = ContentV2CardsUpdatePostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsUpdatePost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2CardsUpdatePost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsUpdatePostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsUploadAddPostRequest handles POST /content/v2/cards/upload/add operation. // // Метод создаёт новые карточки товаров, присоединяя их // к существующим карточкам. // Габариты товаров можно указать только в `сантиметрах`, // // вес товара с упаковкой — в `килограммах`. // //

// Создание карточки товара происходит асинхронно. // После отправки запрос становится в очередь на // обработку.
Максимальный размер запроса 10 Мб.
// Если ответ `Успешно` (`200`), но какие-то карточки не // обновились, получите [список несозданных карточек // товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get). //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня для метода будет отдельный // лимит — 10 запросов в минуту на один аккаунт продавца //
. // // POST /content/v2/cards/upload/add func (s *Server) handleContentV2CardsUploadAddPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/cards/upload/add"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsUploadAddPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsUploadAddPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsUploadAddPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2CardsUploadAddPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2CardsUploadAddPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsUploadAddPostOperation, OperationSummary: "Создание карточек товаров с присоединением", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = OptContentV2CardsUploadAddPostReq Params = struct{} Response = ContentV2CardsUploadAddPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsUploadAddPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2CardsUploadAddPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsUploadAddPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2CardsUploadPostRequest handles POST /content/v2/cards/upload operation. // // Метод создаёт карточки товаров c указанием описаний и // характеристик товаров.
//
// Есть две формы запроса: для создания отдельных и // объединённых карточек товаров. //
// Габариты товаров можно указать только в `сантиметрах`, // // вес товара с упаковкой — в `килограммах`. // //

// Создание карточки товара происходит асинхронно. // После отправки запрос становится в очередь на // обработку.
// В одном запросе можно создать максимум 100 // объединённых карточек товаров (`imtID`), по 30 карточек // товаров в каждой. Максимальный размер запроса 10 Мб.
// Если ответ `Успешно` (`200`), но какие-то карточки не // обновились, получите [список несозданных карточек // товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get). //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня для метода будет отдельный // лимит — 10 запросов в минуту на один аккаунт продавца //
. // // POST /content/v2/cards/upload func (s *Server) handleContentV2CardsUploadPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/cards/upload"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2CardsUploadPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2CardsUploadPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2CardsUploadPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2CardsUploadPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2CardsUploadPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2CardsUploadPostOperation, OperationSummary: "Создание карточек товаров", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = []ContentV2CardsUploadPostReqItem Params = struct{} Response = ContentV2CardsUploadPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2CardsUploadPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2CardsUploadPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2CardsUploadPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectoryColorsGetRequest handles GET /content/v2/directory/colors operation. // // Метод предоставляет возможные значения // [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Цвет`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/colors func (s *Server) handleContentV2DirectoryColorsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/colors"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectoryColorsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectoryColorsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectoryColorsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectoryColorsGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectoryColorsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectoryColorsGetOperation, OperationSummary: "Цвет", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectoryColorsGetParams Response = ContentV2DirectoryColorsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectoryColorsGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectoryColorsGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectoryColorsGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectoryColorsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectoryCountriesGetRequest handles GET /content/v2/directory/countries operation. // // Метод предоставляет возможные значения // [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Страна производства`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/countries func (s *Server) handleContentV2DirectoryCountriesGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/countries"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectoryCountriesGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectoryCountriesGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectoryCountriesGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectoryCountriesGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectoryCountriesGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectoryCountriesGetOperation, OperationSummary: "Страна производства", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectoryCountriesGetParams Response = ContentV2DirectoryCountriesGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectoryCountriesGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectoryCountriesGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectoryCountriesGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectoryCountriesGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectoryKindsGetRequest handles GET /content/v2/directory/kinds operation. // // Метод предоставляет возможные значения // [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Пол`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/kinds func (s *Server) handleContentV2DirectoryKindsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/kinds"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectoryKindsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectoryKindsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectoryKindsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectoryKindsGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectoryKindsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectoryKindsGetOperation, OperationSummary: "Пол", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectoryKindsGetParams Response = ContentV2DirectoryKindsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectoryKindsGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectoryKindsGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectoryKindsGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectoryKindsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectorySeasonsGetRequest handles GET /content/v2/directory/seasons operation. // // Метод предоставляет возможные значения // [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Сезон`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/seasons func (s *Server) handleContentV2DirectorySeasonsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/seasons"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectorySeasonsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectorySeasonsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectorySeasonsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectorySeasonsGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectorySeasonsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectorySeasonsGetOperation, OperationSummary: "Сезон", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectorySeasonsGetParams Response = ContentV2DirectorySeasonsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectorySeasonsGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectorySeasonsGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectorySeasonsGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectorySeasonsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectoryTnvedGetRequest handles GET /content/v2/directory/tnved operation. // // Метод предоставляет список ТНВЭД-кодов по ID // [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get) и фрагменту ТНВЭД-кода. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/tnved func (s *Server) handleContentV2DirectoryTnvedGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/tnved"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectoryTnvedGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectoryTnvedGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectoryTnvedGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectoryTnvedGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectoryTnvedGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectoryTnvedGetOperation, OperationSummary: "ТНВЭД-код", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "subjectID", In: "query", }: params.SubjectID, { Name: "search", In: "query", }: params.Search, { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectoryTnvedGetParams Response = ContentV2DirectoryTnvedGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectoryTnvedGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectoryTnvedGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectoryTnvedGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectoryTnvedGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2DirectoryVatGetRequest handles GET /content/v2/directory/vat operation. // // Метод предоставляет возможные значения // [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Ставка НДС`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/directory/vat func (s *Server) handleContentV2DirectoryVatGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/directory/vat"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2DirectoryVatGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2DirectoryVatGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2DirectoryVatGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2DirectoryVatGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2DirectoryVatGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2DirectoryVatGetOperation, OperationSummary: "Ставка НДС", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2DirectoryVatGetParams Response = ContentV2DirectoryVatGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2DirectoryVatGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2DirectoryVatGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2DirectoryVatGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2DirectoryVatGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2GetCardsListPostRequest handles POST /content/v2/get/cards/list operation. // //
// Метод доступен по токену с // категорией Контент или Продвижение //
// Метод предоставляет список созданных карточек // товаров. //
// В ответе метода не будет карточек, находящихся в // корзине. Получить такие карточки можно через отдельный метод. //
// Чтобы получить **больше 100** карточек товаров, // воспользуйтесь пагинацией: //
    //
  1. Сделайте первый запрос:
    //
    // {
    // "settings": {
    // "cursor": {
    // "limit": 100
    // },
    // "filter": {
    // "withPhoto": -1
    // }
    // }
    // }
    //
  2. //
  3. Пройдите в конец полученного списка карточек // товаров.
  4. //
  5. Скопируйте из cursor две строки: //
  6. //
  7. Вставьте скопированные строки в параметр запроса // cursor.
  8. //
  9. Повторите запрос.
  10. //
  11. Повторяйте пункты со 2 по 5, пока поле // total в ответе не станет меньше чем параметр // limit в запросе. Это будет означать, что вы // получили все карточки. //
//
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/get/cards/list func (s *Server) handleContentV2GetCardsListPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/get/cards/list"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2GetCardsListPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2GetCardsListPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2GetCardsListPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2GetCardsListPostParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeContentV2GetCardsListPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2GetCardsListPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2GetCardsListPostOperation, OperationSummary: "Список карточек товаров", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = *ContentV2GetCardsListPostReq Params = ContentV2GetCardsListPostParams Response = ContentV2GetCardsListPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2GetCardsListPostParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2GetCardsListPost(ctx, request, params) return response, err }, ) } else { response, err = s.h.ContentV2GetCardsListPost(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2GetCardsListPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2GetCardsTrashPostRequest handles POST /content/v2/get/cards/trash operation. // //
// Метод доступен по токену с // категорией Контент или Продвижение //
// Метод предоставляет список карточек товаров в // корзине.

// Чтобы получить **больше 100** карточек товаров, // воспользуйтесь пагинацией: //
    //
  1. Сделайте первый запрос:
    //
    // {
    // "settings": {
    // "cursor": {
    // "limit": 100
    // },
    // "filter": {
    // "withPhoto": -1
    // }
    // }
    // }
    //
  2. //
  3. Пройдите в конец полученного списка карточек // товаров.
  4. //
  5. Скопируйте из cursor две строки: //
  6. //
  7. Вставьте скопированные строки в параметр запроса // cursor.
  8. //
  9. Повторите запрос.
  10. //
  11. Повторяйте пункты со 2 по 5, пока поле // total в ответе не станет меньше чем параметр // limit в запросе. Это будет означать, что вы // получили все карточки. //
//
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/get/cards/trash func (s *Server) handleContentV2GetCardsTrashPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/get/cards/trash"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2GetCardsTrashPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2GetCardsTrashPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2GetCardsTrashPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2GetCardsTrashPostParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeContentV2GetCardsTrashPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2GetCardsTrashPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2GetCardsTrashPostOperation, OperationSummary: "Список карточек товаров в корзине", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = *ContentV2GetCardsTrashPostReq Params = ContentV2GetCardsTrashPostParams Response = ContentV2GetCardsTrashPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2GetCardsTrashPostParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2GetCardsTrashPost(ctx, request, params) return response, err }, ) } else { response, err = s.h.ContentV2GetCardsTrashPost(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2GetCardsTrashPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2ObjectAllGetRequest handles GET /content/v2/object/all operation. // // Метод предоставляет список названий [родительских // категорий // предметов](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1parent~1all/get) и их предметов с ID. Например, у категории `Игрушки` будут предметы `Калейдоскопы`, `Куклы`, `Мячики`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/object/all func (s *Server) handleContentV2ObjectAllGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/object/all"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2ObjectAllGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2ObjectAllGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2ObjectAllGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2ObjectAllGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2ObjectAllGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2ObjectAllGetOperation, OperationSummary: "Список предметов", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, { Name: "name", In: "query", }: params.Name, { Name: "limit", In: "query", }: params.Limit, { Name: "offset", In: "query", }: params.Offset, { Name: "parentID", In: "query", }: params.ParentID, }, Raw: r, } type ( Request = struct{} Params = ContentV2ObjectAllGetParams Response = ContentV2ObjectAllGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2ObjectAllGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2ObjectAllGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2ObjectAllGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2ObjectAllGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2ObjectCharcsSubjectIdGetRequest handles GET /content/v2/object/charcs/{subjectId} operation. // // Метод предоставляет параметры характеристик // предмета: названия, типы данных, единицы измерения и // так далее. В запросе необходимо указать ID // [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get). //
// Для получения характеристик Цвет, Пол, Страна производства, Сезон, Ставка НДС и ТНВЭД-код используйте отдельные методы //
//
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/object/charcs/{subjectId} func (s *Server) handleContentV2ObjectCharcsSubjectIdGetRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/object/charcs/{subjectId}"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2ObjectCharcsSubjectIdGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2ObjectCharcsSubjectIdGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2ObjectCharcsSubjectIdGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2ObjectCharcsSubjectIdGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2ObjectCharcsSubjectIdGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2ObjectCharcsSubjectIdGetOperation, OperationSummary: "Характеристики предмета", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "subjectId", In: "path", }: params.SubjectId, { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2ObjectCharcsSubjectIdGetParams Response = ContentV2ObjectCharcsSubjectIdGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2ObjectCharcsSubjectIdGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2ObjectCharcsSubjectIdGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2ObjectCharcsSubjectIdGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2ObjectCharcsSubjectIdGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2ObjectParentAllGetRequest handles GET /content/v2/object/parent/all operation. // // Метод предоставляет названия и ID всех родительских // категорий для [создания карточек // товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov): например, // `Электроника`, `Бытовая химия`, `Рукоделие`. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/object/parent/all func (s *Server) handleContentV2ObjectParentAllGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/object/parent/all"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2ObjectParentAllGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2ObjectParentAllGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2ObjectParentAllGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV2ObjectParentAllGetParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } var response ContentV2ObjectParentAllGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2ObjectParentAllGetOperation, OperationSummary: "Родительские категории товаров", OperationID: "", Body: nil, Params: middleware.Parameters{ { Name: "locale", In: "query", }: params.Locale, }, Raw: r, } type ( Request = struct{} Params = ContentV2ObjectParentAllGetParams Response = ContentV2ObjectParentAllGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV2ObjectParentAllGetParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2ObjectParentAllGet(ctx, params) return response, err }, ) } else { response, err = s.h.ContentV2ObjectParentAllGet(ctx, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2ObjectParentAllGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2TagNomenclatureLinkPostRequest handles POST /content/v2/tag/nomenclature/link operation. // // Метод добавляет или снимает ярлык с карточки товара. // К карточке можно добавить максимум 15 ярлыков.
// При удалении ярлыка из карточки товара он не // удаляется из [списка // ярлыков](/openapi/work-with-products#tag/Yarlyki/paths/~1content~1v2~1tags/get) // продавца. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v2/tag/nomenclature/link func (s *Server) handleContentV2TagNomenclatureLinkPostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v2/tag/nomenclature/link"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2TagNomenclatureLinkPostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2TagNomenclatureLinkPostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2TagNomenclatureLinkPostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV2TagNomenclatureLinkPostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV2TagNomenclatureLinkPostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2TagNomenclatureLinkPostOperation, OperationSummary: "Управление ярлыками в карточке товара", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *ContentV2TagNomenclatureLinkPostReq Params = struct{} Response = ContentV2TagNomenclatureLinkPostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2TagNomenclatureLinkPost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV2TagNomenclatureLinkPost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2TagNomenclatureLinkPostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV2TagsGetRequest handles GET /content/v2/tags operation. // // Метод предоставляет список и характеристики всех // ярлыков продавца для группировки и фильтрации // товаров. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // GET /content/v2/tags func (s *Server) handleContentV2TagsGetRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/content/v2/tags"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV2TagsGetOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV2TagsGetOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV2TagsGetOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } var response ContentV2TagsGetRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV2TagsGetOperation, OperationSummary: "Список ярлыков", OperationID: "", Body: nil, Params: middleware.Parameters{}, Raw: r, } type ( Request = struct{} Params = struct{} Response = ContentV2TagsGetRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV2TagsGet(ctx) return response, err }, ) } else { response, err = s.h.ContentV2TagsGet(ctx) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV2TagsGetResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV3MediaFilePostRequest handles POST /content/v3/media/file operation. // // Метод загружает и добавляет один медиафайл к // карточке товара. // Требования к изображениям: // * максимум изображений для одной карточки товара — 30 // * минимальное разрешение — 700x900 px // * максимальный размер — 32 Мб // * минимальное качество — 65% // * форматы — JPG, PNG, BMP, GIF (статичные), WebP // Требования к видео: // * максимум одно видео для одной карточки товара // * максимальный размер — 50 Мб // * форматы — MOV, MP4 //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v3/media/file func (s *Server) handleContentV3MediaFilePostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v3/media/file"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV3MediaFilePostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV3MediaFilePostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV3MediaFilePostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } params, err := decodeContentV3MediaFilePostParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } request, close, err := s.decodeContentV3MediaFilePostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV3MediaFilePostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV3MediaFilePostOperation, OperationSummary: "Загрузить медиафайл", OperationID: "", Body: request, Params: middleware.Parameters{ { Name: "X-Nm-Id", In: "header", }: params.XNmID, { Name: "X-Photo-Number", In: "header", }: params.XPhotoNumber, }, Raw: r, } type ( Request = *ContentV3MediaFilePostReq Params = ContentV3MediaFilePostParams Response = ContentV3MediaFilePostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, unpackContentV3MediaFilePostParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV3MediaFilePost(ctx, request, params) return response, err }, ) } else { response, err = s.h.ContentV3MediaFilePost(ctx, request, params) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV3MediaFilePostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } } // handleContentV3MediaSavePostRequest handles POST /content/v3/media/save operation. // // Метод загружает набор медиафайлов в карточку товара // через указание ссылок в запросе. //
// Новые медиафайлы полностью заменяют старые. Чтобы // добавить новые медиафайлы, укажите в запросе ссылки // одновременно на новые и старые медиафайлы. //
// Требования к изображениям: // * максимум изображений для одной карточки товара — 30 // * минимальное разрешение — 700×900 px // * максимальный размер — 32 Мб // * минимальное качество — 65% // * форматы — JPG, PNG, BMP, GIF (статичные), WebP // Требования к видео: // * максимум одно видео для одной карточки товара // * максимальный размер — 50 Мб // * форматы — MOV, MP4 // Если видео или хотя бы одно изображение в запросе не // соответствует требованиям, то даже при успешном // ответе ни одно изображение/видео не загрузится. //
// Максимум 100 запросов в минуту для всех // методов категории Контент на один // аккаунт продавца. С 5 июня — за исключением методов создания, создания с присоединением и редактирования карточек товаров //
. // // POST /content/v3/media/save func (s *Server) handleContentV3MediaSavePostRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/content/v3/media/save"), } // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ContentV3MediaSavePostOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) defer span.End() // Add Labeler to context. labeler := &Labeler{attrs: otelAttrs} ctx = contextWithLabeler(ctx, labeler) // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() code := statusWriter.status if code != 0 { codeAttr := semconv.HTTPResponseStatusCode(code) attrs = append(attrs, codeAttr) span.SetAttributes(codeAttr) } attrOpt := metric.WithAttributes(attrs...) // Increment request counter. s.requests.Add(ctx, 1, attrOpt) // Use floating point division here for higher precision (instead of Millisecond method). s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) }() var ( recordError = func(stage string, err error) { span.RecordError(err) // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status if code >= 100 && code < 500 { span.SetStatus(codes.Error, stage) } attrSet := labeler.AttributeSet() attrs := attrSet.ToSlice() if code != 0 { attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) } s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) } err error opErrContext = ogenerrors.OperationContext{ Name: ContentV3MediaSavePostOperation, ID: "", } ) { type bitset = [1]uint8 var satisfied bitset { sctx, ok, err := s.securityHeaderApiKey(ctx, ContentV3MediaSavePostOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Security: "HeaderApiKey", Err: err, } defer recordError("Security:HeaderApiKey", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if ok { satisfied[0] |= 1 << 0 ctx = sctx } } if ok := func() bool { nextRequirement: for _, requirement := range []bitset{ {0b00000001}, } { for i, mask := range requirement { if satisfied[i]&mask != mask { continue nextRequirement } } return true } return false }(); !ok { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, } defer recordError("Security", err) s.cfg.ErrorHandler(ctx, w, r, err) return } } request, close, err := s.decodeContentV3MediaSavePostRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, Err: err, } defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } defer func() { if err := close(); err != nil { recordError("CloseRequest", err) } }() var response ContentV3MediaSavePostRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, OperationName: ContentV3MediaSavePostOperation, OperationSummary: "Загрузить медиафайлы по ссылкам", OperationID: "", Body: request, Params: middleware.Parameters{}, Raw: r, } type ( Request = *ContentV3MediaSavePostReq Params = struct{} Response = ContentV3MediaSavePostRes ) response, err = middleware.HookMiddleware[ Request, Params, Response, ]( m, mreq, nil, func(ctx context.Context, request Request, params Params) (response Response, err error) { response, err = s.h.ContentV3MediaSavePost(ctx, request) return response, err }, ) } else { response, err = s.h.ContentV3MediaSavePost(ctx, request) } if err != nil { defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeContentV3MediaSavePostResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } return } }