github.com/cloudwego/kitex@v0.9.0/pkg/generic/descriptor/http_mapping.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package descriptor
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  
    23  	"github.com/cloudwego/kitex/pkg/generic/proto"
    24  )
    25  
    26  // HTTPMapping http mapping annotation
    27  type HTTPMapping interface {
    28  	// get value from request
    29  	Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error)
    30  	// set value to response
    31  	Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error
    32  }
    33  
    34  // NewHTTPMapping HTTPMapping creator
    35  // api.query = value
    36  type NewHTTPMapping func(value string) HTTPMapping
    37  
    38  // DefaultNewMapping the default mapping creator
    39  var DefaultNewMapping = NewAPIBody
    40  
    41  var (
    42  	// APIQueryAnnotation api.path annotation
    43  	APIQueryAnnotation = NewBAMAnnotation("api.query", NewAPIQuery)
    44  	// APIPathAnnotation api.path annotation
    45  	APIPathAnnotation = NewBAMAnnotation("api.path", NewAPIPath)
    46  	// APIHeaderAnnotation api.header annotation
    47  	APIHeaderAnnotation = NewBAMAnnotation("api.header", NewAPIHeader)
    48  	// APICookieAnnotation api.cookie annotation
    49  	APICookieAnnotation = NewBAMAnnotation("api.cookie", NewAPICookie)
    50  	// APIBodyAnnotation api.body annotation
    51  	APIBodyAnnotation = NewBAMAnnotation("api.body", NewAPIBody)
    52  	// APIHttpCodeAnnotation api.http_code annotation
    53  	APIHttpCodeAnnotation = NewBAMAnnotation("api.http_code", NewAPIHTTPCode)
    54  	// APINoneAnnotation api.none annotation
    55  	APINoneAnnotation = NewBAMAnnotation("api.none", NewAPINone)
    56  	// APIRawBodyAnnotation api.raw_body annotation
    57  	APIRawBodyAnnotation = NewBAMAnnotation("api.raw_body", NewAPIRawBody)
    58  )
    59  
    60  // api.query = xx
    61  type apiQuery struct {
    62  	value string // == xx
    63  }
    64  
    65  // NewAPIQuery ...
    66  var NewAPIQuery NewHTTPMapping = func(value string) HTTPMapping {
    67  	return &apiQuery{value}
    68  }
    69  
    70  func (m *apiQuery) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
    71  	val := req.GetQuery(m.value)
    72  	return val, val != "", nil
    73  }
    74  
    75  func (*apiQuery) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
    76  	return nil
    77  }
    78  
    79  // api.path = xx
    80  type apiPath struct {
    81  	value string
    82  }
    83  
    84  // NewAPIPath ...
    85  var NewAPIPath NewHTTPMapping = func(value string) HTTPMapping {
    86  	return &apiPath{value}
    87  }
    88  
    89  func (m *apiPath) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
    90  	val := req.Params.ByName(m.value)
    91  	return val, val != "", nil
    92  }
    93  
    94  func (*apiPath) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
    95  	return nil
    96  }
    97  
    98  // api.header = xx
    99  type apiHeader struct {
   100  	value string
   101  }
   102  
   103  // NewAPIHeader ...
   104  var NewAPIHeader NewHTTPMapping = func(value string) HTTPMapping {
   105  	return &apiHeader{value}
   106  }
   107  
   108  func (m *apiHeader) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   109  	val := req.GetHeader(m.value)
   110  	return val, val != "", nil
   111  }
   112  
   113  func (m *apiHeader) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   114  	resp.Header.Set(m.value, convertToString(val))
   115  	return nil
   116  }
   117  
   118  // api.cookie = xx
   119  type apiCookie struct {
   120  	value string
   121  }
   122  
   123  // NewAPICookie ...
   124  var NewAPICookie NewHTTPMapping = func(value string) HTTPMapping {
   125  	return &apiCookie{value}
   126  }
   127  
   128  func (m *apiCookie) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   129  	val := req.GetCookie(m.value)
   130  	if val == "" {
   131  		return val, false, nil
   132  	}
   133  	return val, true, nil
   134  }
   135  
   136  func (m *apiCookie) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   137  	return nil
   138  }
   139  
   140  // api.body = xx
   141  type apiBody struct {
   142  	value string
   143  }
   144  
   145  // NewAPIBody ...
   146  var NewAPIBody NewHTTPMapping = func(value string) HTTPMapping {
   147  	return &apiBody{value}
   148  }
   149  
   150  func (m *apiBody) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   151  	switch req.ContentType {
   152  	case "", MIMEApplicationJson:
   153  		val, ok := req.Body[m.value]
   154  		return val, ok, nil
   155  	case MIMEApplicationProtobuf:
   156  		msg := req.GeneralBody.(proto.Message)
   157  		val, err := msg.TryGetFieldByNumber(int(field.ID))
   158  		return val, err == nil, nil
   159  	default:
   160  		return nil, false, errors.New("unsupported request content type")
   161  	}
   162  }
   163  
   164  func (m *apiBody) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   165  	switch resp.ContentType {
   166  	case "", MIMEApplicationJson:
   167  		resp.Body[m.value] = val
   168  		return nil
   169  	case MIMEApplicationProtobuf:
   170  		msg := resp.GeneralBody.(proto.Message)
   171  		return msg.TrySetFieldByNumber(int(field.ID), val)
   172  	default:
   173  		return errors.New("unsupported response content type")
   174  	}
   175  }
   176  
   177  type apiHTTPCode struct{}
   178  
   179  // NewAPIHTTPCode ...
   180  var NewAPIHTTPCode NewHTTPMapping = func(value string) HTTPMapping {
   181  	return &apiHTTPCode{}
   182  }
   183  
   184  func (m *apiHTTPCode) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   185  	return nil, false, nil
   186  }
   187  
   188  func (m *apiHTTPCode) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   189  	resp.StatusCode = convertToInt32(val)
   190  	return nil
   191  }
   192  
   193  type apiNone struct{}
   194  
   195  // NewAPINone ...
   196  var NewAPINone NewHTTPMapping = func(value string) HTTPMapping {
   197  	return &apiNone{}
   198  }
   199  
   200  func (m *apiNone) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   201  	return nil, false, nil
   202  }
   203  
   204  func (m *apiNone) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   205  	return nil
   206  }
   207  
   208  type apiRawBody struct{}
   209  
   210  // NewAPIRawBody ...
   211  var NewAPIRawBody NewHTTPMapping = func(value string) HTTPMapping {
   212  	return &apiRawBody{}
   213  }
   214  
   215  func (m *apiRawBody) Request(ctx context.Context, req *HTTPRequest, field *FieldDescriptor) (interface{}, bool, error) {
   216  	return req.RawBody, true, nil
   217  }
   218  
   219  func (m *apiRawBody) Response(ctx context.Context, resp *HTTPResponse, field *FieldDescriptor, val interface{}) error {
   220  	return nil
   221  }