server/server.go
func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// println("Request to the remote service has been established")
	key := getURLParam(r, cfg.QueryCacheKey)
	if key == "" {
		// println("return because key was empty")
		w.WriteHeader(cfg.FailStatus)
		return
	}

	// we always need the Entry, so get it now
	entry := s.store.Get(key)

	if entry == nil && r.Method != methodPost {
		// if it's nil then means it never setted before
		// it doesn't exists, and client doesn't wants to
		// add a cache entry, so just return
		//
		// no delete action is valid
		// no get action is valid
		// no post action is requested
		w.WriteHeader(cfg.FailStatus)
		return
	}

	switch r.Method {
	case methodGet:
		{
			// get from the cache and send to client
			res, ok := entry.Response()
			if !ok {
				// entry exists but it has been expired
				// return
				w.WriteHeader(cfg.FailStatus)
				return
			}

			// entry exists and response is valid
			// send it to the client
			w.Header().Set(cfg.ContentTypeHeader, res.ContentType())
			w.WriteHeader(res.StatusCode())
			w.Write(res.Body())
		}
	case methodPost:
		{
			// save a new cache entry if entry ==nil or
			// update an existing if entry !=nil

			body, err := ioutil.ReadAll(r.Body)
			if err != nil || len(body) == 0 {
				// println("body's request was empty, return fail")
				w.WriteHeader(cfg.FailStatus)
				return
			}

			statusCode, _ := getURLParamInt(r, cfg.QueryCacheStatusCode)
			contentType := getURLParam(r, cfg.QueryCacheContentType)

			// now that we have the information
			// we want to see if this is a totally new cache entry
			// or just update an existing one with the new information
			// (an update can change the status code, content type
			//     and ofcourse the body and expiration time by header)

			if entry == nil {
				// get the information by its url
				// println("we have a post request method, let's save a cached entry ")
				// get the cache expiration via url param
				expirationSeconds, err := getURLParamInt64(r, cfg.QueryCacheDuration)
				// get the body from the requested body
				// get the expiration from the "cache-control's maxage" if no url param is setted
				if expirationSeconds <= 0 || err != nil {
					expirationSeconds = int64(nethttp.GetMaxAge(r)().Seconds())
				}
				// if not setted then try to get it via
				if expirationSeconds <= 0 {
					expirationSeconds = int64(cfg.MinimumCacheDuration.Seconds())
				}

				cacheDuration := time.Duration(expirationSeconds) * time.Second

				// store by its url+the key in order to be unique key among different servers with the same paths
				s.store.Set(key, statusCode, contentType, body, cacheDuration)
			} else {
				// update an existing one and change its duration  based on the header
				// (if > existing duration)
				entry.Reset(statusCode, contentType, body, nethttp.GetMaxAge(r))
			}

			w.WriteHeader(cfg.SuccessStatus)
		}
	case methodDelete:
		{
			// remove the entry entirely from the cache
			// manually DELETE cache should remove this entirely
			// no just invalidate it
			s.store.Remove(key)
			w.WriteHeader(cfg.SuccessStatus)
		}
	default:
		w.WriteHeader(cfg.FailStatus)
	}

}
func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// println("Request to the remote service has been established")
	key := getURLParam(r, cfg.QueryCacheKey)
	if key == "" {
		// println("return because key was empty")
		w.WriteHeader(cfg.FailStatus)
		return
	}

	// we always need the Entry, so get it now
	entry := s.store.Get(key)

	if entry == nil && r.Method != methodPost {
		// if it's nil then means it never setted before
		// it doesn't exists, and client doesn't wants to
		// add a cache entry, so just return
		//
		// no delete action is valid
		// no get action is valid
		// no post action is requested
		w.WriteHeader(cfg.FailStatus)
		return
	}

	switch r.Method {
	case methodGet:
		{
			// get from the cache and send to client
			res, ok := entry.Response()
			if !ok {
				// entry exists but it has been expired
				// return
				w.WriteHeader(cfg.FailStatus)
				return
			}

			// entry exists and response is valid
			// send it to the client
			w.Header().Set(cfg.ContentTypeHeader, res.ContentType())
			w.WriteHeader(res.StatusCode())
			w.Write(res.Body())
		}
	case methodPost:
		{
			// save a new cache entry if entry ==nil or
			// update an existing if entry !=nil

			body, err := ioutil.ReadAll(r.Body)
			if err != nil || len(body) == 0 {
				// println("body's request was empty, return fail")
				w.WriteHeader(cfg.FailStatus)
				return
			}

			statusCode, _ := getURLParamInt(r, cfg.QueryCacheStatusCode)
			contentType := getURLParam(r, cfg.QueryCacheContentType)

			// now that we have the information
			// we want to see if this is a totally new cache entry
			// or just update an existing one with the new information
			// (an update can change the status code, content type
			//     and ofcourse the body and expiration time by header)

			if entry == nil {
				// get the information by its url
				// println("we have a post request method, let's save a cached entry ")
				// get the cache expiration via url param
				expirationSeconds, err := getURLParamInt64(r, cfg.QueryCacheDuration)
				// get the body from the requested body
				// get the expiration from the "cache-control's maxage" if no url param is setted
				if expirationSeconds <= 0 || err != nil {
					expirationSeconds = int64(nethttp.GetMaxAge(r)().Seconds())
				}
				// if not setted then try to get it via
				if expirationSeconds <= 0 {
					expirationSeconds = int64(cfg.MinimumCacheDuration.Seconds())
				}

				cacheDuration := time.Duration(expirationSeconds) * time.Second

				// store by its url+the key in order to be unique key among different servers with the same paths
				s.store.Set(key, statusCode, contentType, body, cacheDuration)
			} else {
				// update an existing one and change its duration  based on the header
				// (if > existing duration)
				entry.Reset(statusCode, contentType, body, nethttp.GetMaxAge(r))
			}

			w.WriteHeader(cfg.SuccessStatus)
		}
	case methodDelete:
		{
			// remove the entry entirely from the cache
			// manually DELETE cache should remove this entirely
			// no just invalidate it
			s.store.Remove(key)
			w.WriteHeader(cfg.SuccessStatus)
		}
	default:
		w.WriteHeader(cfg.FailStatus)
	}

}
// ServeHTTP serves the cache Service to the outside world,
// it is used only when you want to achieve something like horizontal scaling
// it parses the request and tries to return the response with the cached body of the requested cache key
// server-side function