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 }