From ffea7e88a28d2809563bd366944ff71a3e217c1e Mon Sep 17 00:00:00 2001 From: Manu Mtz-Almeida Date: Sat, 30 Aug 2014 22:22:57 +0200 Subject: [PATCH] Working on content type negotiation API --- CHANGELOG.md | 5 ++++ context.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.go | 26 +++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ec8c5ab..c89a3c23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ #Changelog +###Gin 0.5 (Aug 21, 2014) + +- [NEW] Content Negotiation + + ###Gin 0.4 (Aug 21, 2014) - [NEW] Development mode diff --git a/context.go b/context.go index 294d1cce..570314b6 100644 --- a/context.go +++ b/context.go @@ -67,6 +67,7 @@ type Context struct { Engine *Engine handlers []HandlerFunc index int8 + accepted []string } /************************************/ @@ -275,3 +276,75 @@ func (c *Context) Data(code int, contentType string, data []byte) { func (c *Context) File(filepath string) { http.ServeFile(c.Writer, c.Request, filepath) } + +/************************************/ +/******** CONTENT NEGOTIATION *******/ +/************************************/ +type Negotiate struct { + Offered []string + Data interface{} + JsonData interface{} + XMLData interface{} + HTMLData interface{} + HTMLPath string +} + +func (c *Context) Negotiate2(code int, config Negotiate) { + result := c.NegotiateFormat(config.Offered...) + switch result { + case MIMEJSON: + c.JSON(code, config.Data) + + case MIMEHTML: + name := config.HTMLPath + c.HTML(code, name, config.Data) + + case MIMEXML: + c.XML(code, config.Data) + default: + c.Fail(400, errors.New("m")) + } +} + +func (c *Context) Negotiate(code int, config map[string]interface{}, offerts ...string) { + result := c.NegotiateFormat(offerts...) + switch result { + case MIMEJSON: + data := readData("json.data", config) + c.JSON(code, data) + + case MIMEHTML: + data := readData("html.data", config) + name := config["html.path"].(string) + c.HTML(code, name, data) + + case MIMEXML: + data := readData("xml.data", config) + c.XML(code, data) + default: + c.Fail(400, errors.New("m")) + } +} + +func (c *Context) NegotiateFormat(offered ...string) string { + if c.accepted == nil { + c.accepted = parseAccept(c.Request.Header.Get("Accept")) + } + if len(c.accepted) == 0 { + return offered[0] + + } else { + for _, accepted := range c.accepted { + for _, offert := range offered { + if accepted == offert { + return offert + } + } + } + return "" + } +} + +func (c *Context) SetAccepted(formats ...string) { + c.accepted = formats +} diff --git a/utils.go b/utils.go index f58097a4..96d403f4 100644 --- a/utils.go +++ b/utils.go @@ -8,6 +8,7 @@ import ( "encoding/xml" "reflect" "runtime" + "strings" ) type H map[string]interface{} @@ -45,6 +46,31 @@ func filterFlags(content string) string { return content } +func readData(key string, config map[string]interface{}) interface{} { + data, ok := config[key] + if ok { + return data + } + data, ok = config["*.data"] + if !ok { + panic("negotiation config is invalid") + } + return data +} + +func parseAccept(accept string) []string { + parts := strings.Split(accept, ",") + for i, part := range parts { + index := strings.IndexByte(part, ';') + if index >= 0 { + part = part[0:index] + } + part = strings.TrimSpace(part) + parts[i] = part + } + return parts +} + func funcName(f interface{}) string { return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() }