Comments (19)
Is there a way to register a renderer for a custom MediaType?
I want to use something like application/vnd.myapp.person.json;version=1.0.0
as the "preferred" json format and application/json
as a fallback.
from gin.
An API example:
func main() {
r := gin.Default()
r.GET("/hola", func(c *gin.Context) {
data := gin.H{"status": "ok"}
switch c.NegotiateFormat(gin.MIMEHTML, gin.MIMEJSON) {
case gin.MIMEHTML:
c.HTML(200, "resources/hola.tmpl", data)
case gin.MIMEJSON:
c.JSON(200, data)
}
})
}
by default, gin parses the Accept
header.
If you want to change the behaviour, just add a middleware:
r.Use(func(c *gin.Context) {
var format struct {
Format `form:"format"`
}
c.Bind(&format)
switch format.Format {
case "xml":
c.SetNegotiatedFormat(gin.MIMEXML)
case "json" || "":
c.SetNegotiatedFormat(gin.MIMEJSON)
default:
c.Fail(406, "Not Acceptable")
}
})
resource?format=json
from gin.
An update:
c.Negotiate(200, gin.Negotiate{
Offered: []string{gin.MIMEJSON, gin.MIMEXML},
Data: jsonData,
XMLData: xmlData,
})
from gin.
Lines 281 to 338 in 275bdc1
from gin.
@arthurlaveau I did,
I wrote a library to solve the issue. It works with the base go net package.
It works natively with gorilla mux and go-chi.
it could work with gin gonic with a little effort. If you want to contribute feel free
Check the example: https://github.com/Athosone/golib/tree/main/examples/media-type-versioning
from gin.
Interesting!
Anyway, /api/?format=xml/json
, api.json/xml
do not look very standard.
But using the Accept header looks interesting.
Idea, we could add a:
c.Render(code, binding, data)
it should be used like this:
c.Render(200, binding.JSON, data)
and then add a stric-Accept middleware.
from gin.
I'm going out of town for at least a week (vacation :)), so if anyone want to jump in on this, please do.
from gin.
Yeah this popped out at me about gin. I guess I could create a middleware encoder that has the negotiation after the .Next, but it seems like this should be something that is done automatically by gin.
from gin.
I'm interested in this feature as well. It would be nice to have the control to manipulate the response for each format as well.
from gin.
👍 to @alexandernyquist's request for content negotiation
from gin.
I have a proposal for Content Negociation in Gin:
func (c *Context) NegotiatedFormat() string {
if c.negotiatedFormat != "" {
// Evaluate Accept header
c.negotiatedFormat = "application/json" or "application/xml" or "text/html" ...
}
return c.negotiatedFormat
}
This method is lazily initialized, so the performance will not be affected in the current implementation.
It represents the default content negotiation policy but it can be changed with a middleware by calling:
func (c *Context) SetNegotiatedFormat(format string) {
c.negotiatedFormat = format
}
from gin.
How about accepting a file extention in the url like /api/resource.json
and /api/resource.xml
?
from gin.
How about accepting a file extention in the url like /api/resource.json and /api/resource.xml?
Two ideas:
- Using params
func main() {
r := gin.Default()
r.Use(func(c *gin.Context) {
extension := c.Params.ByName("ext")
switch extension {
case "json":
c.SetNegotiatedFormat(gin.MIMEJSON)
case "xml":
c.SetNegotiatedFormat(gin.MIMEJSON)
default:
c.Fail(400, "unknown extension")
}
})
r.GET("/resource.:ext", func(c *gin.Context) {
data := gin.H{"status": "ok"}
switch c.NegotiateFormat(gin.MIMEJSON, gin.MIMEXML) {
case gin.MIMEXML:
c.XML(200, data)
case gin.MIMEJSON:
c.JSON(200, data)
}
})
}
- Using several routes and inspecting the extension:
package main
import "fmt"
import "github.com/gin-gonic/gin"
import "path/filepath"
func main() {
r := gin.Default()
// Create a route group, so this middleware is just applied to this group
negotiation := r.Group("/", func(c *gin.Context) {
switch filepath.Ext(c.Request.URL.Path); {
case "json" || "":
c.SetNegotiatedFormat(gin.MIMEJSON)
case "xml":
c.SetNegotiatedFormat(gin.MIMEJSON)
default:
c.Fail(400, "unknown extension")
}
})
negotiation.GET("/hola.json", resourceHandler)
negotiation.GET("/hola.xml", resourceHandler)
r.Run(":8080")
}
func resourceHandler(c *gin.Context) {
switch c.NegotiateFormat(gin.MIMEJSON, gin.MIMEXML) {
case gin.MIMEXML:
c.XML(200, data)
case gin.MIMEJSON:
c.JSON(200, gin.H{"status": "ok"})
}
}
from gin.
I am also testing a new API:
c.Negotiate(200, gin.H{
"html.file": "resouces/resource.tmpl",
"xml.data": xmlData,
"*.data": jsonData,
})
from gin.
Content.Negotiate()
- Calls c.NegotiateFormat() internally
- Based in the config map, it renders HTML, XML or JSON in a efficient way.
This is extremely flexible, since you can:
- Change the default HTML render, using
engine.HTMLRender = render
- You can change the negotiation algorithm as explained previously using middlewares.
- It doesn't add performance overhead
- Short, imperative and powerful API
from gin.
I think it could be useful to allow extensions to the Negotiate method, because for example the default being an error could not be the best option for everyone, but as it is it is not possible to modify it, without modifying the library code.
from gin.
@jarrodhroberson did you find a way to achieve mediatype versioning?
from gin.
@Athosone about you ? Did you find a way to achieve it ?
from gin.
@Athosone thank you for your answer. I will take a look at it!
from gin.
Related Issues (20)
- please support get parms from Transfer-Encoding:compress-deflate
- unexpected EOF during install HOT 1
- sse panic on fasthttphandler HOT 1
- Will it be made into a more comprehensive framework later on? HOT 4
- How does the gin close the log file? HOT 3
- Should we use url.PathUnescape instead of url.QueryUnescape when UnescapePathValues is true
- go get failed: The requested name is valid, but no data of the requested type was found HOT 1
- Attach Response Headers (or middlewares) to redirected requests (CORS issues) HOT 1
- Should context.GetRawData() also copy body to BodyBytesKey? HOT 3
- YAML BindBody should not parse JSON content HOT 1
- Gin do not support javascript ? HOT 5
- Does gin.Recovery() run before or after Group middleware? HOT 1
- How can i prevent a http connection to close HOT 3
- BasicAuth is not suitable for proxy auth
- Can't get status as expected from context.Status() HOT 1
- Gin Context implementation breaks context.Context contract HOT 3
- [Suggestions] Introducing an AI-powered robot to assist with daily issue and pull request (PR) tasks.
- Need c.JSON() response like behaviour for c.SSEvent() response for supporting first party clients like OpenAI SDK HOT 2
- custom time.Time type can not use bindQuery get a value. HOT 2
- configure server parameters HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gin.