Herkese merhaba!

Uzun yıllardır bol miktarda kişisel zaman ve enerji harcayarak bilgimizi hepinizle paylaşıyoruz. Ancak şu andan itibaren bu blogu çalışır durumda tutabilmek için yardımınıza ihtiyacımız var. Yapmanız gereken tek şey, sitedeki reklamlardan birine tıklamak olacaktır, aksi takdirde hosting vb. masraflar nedeniyle maalesef yayından kaldırılacaktır. Teşekkürler.

HTTP yanıtlarını işlemenin birçok yolu vardır, ancak size neyi beğendiğimi göstereceğim. Projelerimde ilk seçeneği şahsen tercih ediyorum/kullanıyorum çünkü tüm seçenekler isteğe bağlı. Go uygulamalarınızda JSON yanıtları işlemek için belirli bir yönteminiz varsa kullanışlıdır. Üstbilgileri de ayarlayabilirsiniz.


Seçenek 1


package response

import (
"encoding/json"
"errors"
"net/http"
)

type response struct {
code int
headers map[string]string
Action string `json:"action,omitempty"`
Data interface{} `json:"data,omitempty"`
Meta interface{} `json:"meta,omitempty"`
Message string `json:"message,omitempty"`
Errors map[string]string `json:"errors,omitempty"`
}

// Write sends the response to the client. The `response` fields can be
// overridden by passing variadic `opts` ("Functional Options") arguments. If
// no options are given, an empty `200` response is used.
func Write(w http.ResponseWriter, opts ...Option) error {
if len(opts) == 0 {
w.WriteHeader(http.StatusOK)
return nil
}

r := &response{code: http.StatusOK}

for _, opt := range opts {
opt(r)
}

if r.code == 0 {
return errors.New("0 is not a valid code")
}

for k, v := range r.headers {
w.Header().Add(k, v)
}

if !isBodyAllowed(r.code) {
w.WriteHeader(r.code)
return nil
}

body, err := json.Marshal(r)
if err != nil {
return err
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(r.code)

if _, err := w.Write(body); err != nil {
return err
}

return nil
}

// isBodyAllowed reports whether a given response status code permits a body.
// See RFC 7230, section 3.3.
func isBodyAllowed(status int) bool {
if (status >= 100 && status <= 199) || status == 204 || status == 304 {
return false
}

return true
}

// -----------------------------------------------------------------------------

// Option helps overriding/adding response options to the current response.
type Option func(*response)

// Code sets status code.
func Code(code int) Option {
return func(r *response) {
r.code = code
}
}

// Headers adds headers.
func Headers(headers map[string]string) Option {
return func(r *response) {
for k, v := range headers {
r.headers[k] = v
}
}
}

// Success represents "successful" response.
func Success(action string, data interface{}, meta interface{}) Option {
return func(r *response) {
r.Action = action
r.Data = data
r.Meta = meta
r.Message = ""
r.Errors = nil
}
}

// Error represents "failure" response.
func Error(action string, message string, errors map[string]string) Option {
return func(r *response) {
r.Action = action
r.Message = message
r.Errors = errors
r.Data = nil
r.Meta = nil
}
}

Kullanım


response.Write(w)

response.Write(w, response.Code(http.StatusNoContent))

response.Write(w,
response.Code(http.StatusBadRequest),
response.Error("users", "Invalid request", map[string]string{"name":"Required field"}),
)

response.Write(w,
response.Code(http.StatusInternalServerError),
response.Error("users", "Internal error occurred", nil),
)

Seçenek 2


package response

import (
"encoding/json"
"errors"
"net/http"
)

type Response struct {
// Shared common fields.
Code int `json:"-"`
Headers map[string]string `json:"-"`
Action string `json:"action,omitempty"`

// Success specific fields.
Data interface{} `json:"data,omitempty"`
Meta interface{} `json:"meta,omitempty"`

// Failure specific fields.
Message string `json:"message,omitempty"`
Errors map[string]string `json:"errors,omitempty"`
}

func Write(w http.ResponseWriter, r Response) error {
if r.Code == 0 {
return errors.New("0 is not a valid code")
}

for k, v := range r.Headers {
w.Header().Add(k, v)
}

if !isBodyAllowed(r.Code) {
w.WriteHeader(r.Code)
return nil
}

body, err := json.Marshal(r)
if err != nil {
return err
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(r.Code)

if _, err := w.Write(body); err != nil {
return err
}

return nil
}

// See RFC 7230, section 3.3.
func isBodyAllowed(status int) bool {
if (status >= 100 && status <= 199) || status == 204 || status == 304 {
return false
}

return true
}

Kullanım


response.Write(w, response.Response{
Code: http.StatusInternalServerError,
Action: "users",
Message: "An internal error has occurred.",
})

response.Write(w, response.Response{
Code: http.StatusCreated,
Action: "users",
Data: something,
})

response.Write(w, response.Response{Code: http.StatusNoContent})

Seçenek 2


package response

import (
"encoding/json"
"net/http"
)

type Success struct {
Action string `json:"action,omitempty"`
Data interface{} `json:"data,omitempty"`
Meta interface{} `json:"meta,omitempty"`
}

type Error struct {
Action string `json:"action,omitempty"`
Message string `json:"message,omitempty"`
Errors map[string]string `json:"errors,omitempty"`
}

// NewSuccess returns `*Success` instance.
func NewSuccess() *Success {
return &Success{}
}

// NewError returns `*Error` instance.
func NewError() *Error {
return &Error{}
}

// Write calls `write` function to write success response.
func (s *Success) Write(w http.ResponseWriter, code int, headers map[string]string) {
write(w, s, code, headers)
}

// Write calls `write` function to write error response.
func (e *Error) Write(w http.ResponseWriter, code int, headers map[string]string) {
write(w, e, code, headers)
}

// Write writes final response.
func write(w http.ResponseWriter, d interface{}, c int, h map[string]string) error {
if c == 0 {
return errors.New("0 is not a valid code")
}

for k, v := range h {
w.Header().Set(k, v)
}

if !bodyAllowed(c) {
w.WriteHeader(c)
return nil
}

b, e := json.Marshal(d)
if e != nil {
return e
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(c)

if _, e := w.Write(b); e != nil {
return e
}

return nil
}

// bodyAllowed reports whether a given response status code permits a body. See
// RFC 7230, section 3.3.
func bodyAllowed(status int) bool {
if (status >= 100 && status <= 199) || status == 204 || status == 304 {
return false
}

return true
}

Kullanım


response.NewSuccess().Write(w, http.StatusNoContent, nil)

res := response.NewError()
res.Action = "users"
res.Message = "Invalid request"
res.Errors = map[string]string{"name":"Required field"}
res.Write(w, http.StatusBadRequest, nil)

res := response.NewError()
res.Action = "users"
res.Write(w, http.StatusInternalServerError, nil)

Örnek yanıt


500 Internal Server Error
{
"action": "users",
"message": "An internal error has occurred."
}

400 Bad Request
{
"action": "users",
"message": "An invalid request was provided.",
"errors": {
"address": "Invalid value.",
"name": "Invalid value."
}
}

200 OK
{
"action": "users",
"data": {
"uuid": "ac6ae584-7820-4104-ab1d-06bafb07cc65",
"name": "Name",
"address": "Address"
}
}