mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Add batch endpoint (#19)
* add batch endpoint. * keep error code. * use utils.HttpSuccess. * add batch to openapi. * body omitempty.
This commit is contained in:
parent
fb8462b56a
commit
3c3042d691
123
internal/http/batch.go
Normal file
123
internal/http/batch.go
Normal file
@ -0,0 +1,123 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/demodesk/neko/pkg/types"
|
||||
"github.com/demodesk/neko/pkg/utils"
|
||||
)
|
||||
|
||||
type BatchRequest struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
Body json.RawMessage `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
type BatchResponse struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
Body json.RawMessage `json:"body,omitempty"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (b *BatchResponse) Error(httpErr *utils.HTTPError) (err error) {
|
||||
b.Body, err = json.Marshal(httpErr)
|
||||
b.Status = httpErr.Code
|
||||
return
|
||||
}
|
||||
|
||||
type batchHandler struct {
|
||||
Router types.Router
|
||||
PathPrefix string
|
||||
Excluded []string
|
||||
}
|
||||
|
||||
func (b *batchHandler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
var requests []BatchRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&requests); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
responses := make([]BatchResponse, len(requests))
|
||||
for i, request := range requests {
|
||||
res := BatchResponse{
|
||||
Path: request.Path,
|
||||
Method: request.Method,
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(request.Path, b.PathPrefix) {
|
||||
res.Error(utils.HttpBadRequest("this path is not allowed in batch requests"))
|
||||
responses[i] = res
|
||||
continue
|
||||
}
|
||||
|
||||
if exists, _ := utils.ArrayIn(request.Path, b.Excluded); exists {
|
||||
res.Error(utils.HttpBadRequest("this path is excluded from batch requests"))
|
||||
responses[i] = res
|
||||
continue
|
||||
}
|
||||
|
||||
// prepare request
|
||||
req, err := http.NewRequest(request.Method, request.Path, bytes.NewBuffer(request.Body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy headers
|
||||
for k, vv := range r.Header {
|
||||
for _, v := range vv {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// execute request
|
||||
rr := newResponseRecorder()
|
||||
b.Router.ServeHTTP(rr, req)
|
||||
|
||||
// read response
|
||||
body, err := io.ReadAll(rr.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write response
|
||||
responses[i] = BatchResponse{
|
||||
Path: request.Path,
|
||||
Method: request.Method,
|
||||
Body: body,
|
||||
Status: rr.Code,
|
||||
}
|
||||
}
|
||||
|
||||
return utils.HttpSuccess(w, responses)
|
||||
}
|
||||
|
||||
type responseRecorder struct {
|
||||
Code int
|
||||
HeaderMap http.Header
|
||||
Body *bytes.Buffer
|
||||
}
|
||||
|
||||
func newResponseRecorder() *responseRecorder {
|
||||
return &responseRecorder{
|
||||
Code: http.StatusOK,
|
||||
HeaderMap: make(http.Header),
|
||||
Body: new(bytes.Buffer),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *responseRecorder) Header() http.Header {
|
||||
return w.HeaderMap
|
||||
}
|
||||
|
||||
func (w *responseRecorder) Write(b []byte) (int, error) {
|
||||
return w.Body.Write(b)
|
||||
}
|
||||
|
||||
func (w *responseRecorder) WriteHeader(code int) {
|
||||
w.Code = code
|
||||
}
|
@ -42,6 +42,16 @@ func New(WebSocketManager types.WebSocketManager, ApiManager types.ApiManager, c
|
||||
return config.AllowOrigin(r.Header.Get("Origin"))
|
||||
}))
|
||||
|
||||
batch := batchHandler{
|
||||
Router: router,
|
||||
PathPrefix: "/api",
|
||||
Excluded: []string{
|
||||
"/api/batch", // do not allow batchception
|
||||
"/api/ws",
|
||||
},
|
||||
}
|
||||
router.Post("/api/batch", batch.Handle)
|
||||
|
||||
router.Get("/health", func(w http.ResponseWriter, r *http.Request) error {
|
||||
_, err := w.Write([]byte("true"))
|
||||
return err
|
||||
|
52
openapi.yaml
52
openapi.yaml
@ -38,6 +38,28 @@ paths:
|
||||
'200':
|
||||
description: OK
|
||||
|
||||
/api/batch:
|
||||
post:
|
||||
summary: batch
|
||||
operationId: batch
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/BatchResponse'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/BatchRequest'
|
||||
required: true
|
||||
|
||||
#
|
||||
# session
|
||||
#
|
||||
@ -930,6 +952,36 @@ components:
|
||||
message:
|
||||
type: string
|
||||
|
||||
BatchRequest:
|
||||
type: object
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
method:
|
||||
type: string
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
- DELETE
|
||||
body:
|
||||
description: Request body
|
||||
|
||||
BatchResponse:
|
||||
type: object
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
method:
|
||||
type: string
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
- DELETE
|
||||
body:
|
||||
description: Response body
|
||||
status:
|
||||
type: integer
|
||||
|
||||
#
|
||||
# session
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user