Skip to content
Snippets Groups Projects
Commit 8d0892c7 authored by Yordan Kinkov's avatar Yordan Kinkov
Browse files

Create SET cache endpoint

parent 6924e7b5
No related branches found
No related tags found
1 merge request!3Create SET cache endpoint
Showing
with 525 additions and 128 deletions
# Cache
# Cache service
Cache exposes HTTP interface for working with Redis.
\ No newline at end of file
Cache service exposes HTTP interface for working with Redis.
### Basic Architecture
```mermaid
flowchart LR
A[Client] -- request --> B[Cache Service] --> C[(Redis)]
```
### API Documentation
The API Documentation is accessible at `/swagger-ui` path in OAS 3.0 format.
Example: `http://localhost:8080/swagger-ui`
### Dependencies
There must be a running instance of [Redis](https://redis.io/) visible to the service.
The address, username and password of the Redis in-memory store instance must be provided as environment variables.
Example:
```
REDIS_ADDR="localhost:6379"
REDIS_USER="user"
REDIS_PASS="pass"
```
### Development
This service uses [Goa framework](https://goa.design/) v3 as a backbone. [This](https://goa.design/learn/getting-started/) is a good starting point for learning to use the framework.
### Dependencies and Vendor
The project uses Go modules for managing dependencies and we commit the `vendor` directory.
When you add/change dependencies, be sure to clean and update the `vendor` directory before
submitting your Merge Request for review.
```shell
go mod tidy
go mod vendor
```
### Tests and Linters
To execute the units tests for the service go to the root project directory and run:
```go
go test -race ./...
```
To run the linters go to the root project directory and run:
```go
golangci-lint run
```
......@@ -41,10 +41,10 @@ var _ = Service("cache", func() {
Description("Cache service allows storing and retrieving data from distributed cache.")
Method("Get", func() {
Description("Get value from the cache. The result is a sequence of bytes which the client must decode.")
Description("Get JSON value from the cache.")
Payload(CacheGetRequest)
Result(Bytes)
Result(Any)
HTTP(func() {
GET("/v1/cache")
......@@ -59,7 +59,33 @@ var _ = Service("cache", func() {
Example("administration")
})
Response(StatusOK)
Response(StatusOK, func() {
ContentType("application/json")
})
})
})
Method("Set", func() {
Description("Set a JSON value in the cache.")
Payload(CacheSetRequest)
Result(Empty)
HTTP(func() {
POST("/v1/cache")
Header("key:x-cache-key", String, "Cache entry key", func() {
Example("did:web:example.com")
})
Header("namespace:x-cache-namespace", String, "Cache entry namespace", func() {
Example("Login")
})
Header("scope:x-cache-scope", String, "Cache entry scope", func() {
Example("administration")
})
Body("data")
Response(StatusCreated)
})
})
})
......
......@@ -9,3 +9,11 @@ var CacheGetRequest = Type("CacheGetRequest", func() {
Field(3, "scope", String) // Initial implementation with a single scope
Required("key", "namespace", "scope")
})
var CacheSetRequest = Type("CacheSetRequest", func() {
Field(1, "data", Any)
Field(2, "key", String)
Field(3, "namespace", String)
Field(4, "scope", String) // Initial implementation with a single scope
Required("data", "key", "namespace", "scope")
})
......@@ -16,21 +16,29 @@ import (
// Client is the "cache" service client.
type Client struct {
GetEndpoint goa.Endpoint
SetEndpoint goa.Endpoint
}
// NewClient initializes a "cache" service client given the endpoints.
func NewClient(get goa.Endpoint) *Client {
func NewClient(get, set goa.Endpoint) *Client {
return &Client{
GetEndpoint: get,
SetEndpoint: set,
}
}
// Get calls the "Get" endpoint of the "cache" service.
func (c *Client) Get(ctx context.Context, p *CacheGetRequest) (res []byte, err error) {
func (c *Client) Get(ctx context.Context, p *CacheGetRequest) (res interface{}, err error) {
var ires interface{}
ires, err = c.GetEndpoint(ctx, p)
if err != nil {
return
}
return ires.([]byte), nil
return ires.(interface{}), nil
}
// Set calls the "Set" endpoint of the "cache" service.
func (c *Client) Set(ctx context.Context, p *CacheSetRequest) (err error) {
_, err = c.SetEndpoint(ctx, p)
return
}
......@@ -16,18 +16,21 @@ import (
// Endpoints wraps the "cache" service endpoints.
type Endpoints struct {
Get goa.Endpoint
Set goa.Endpoint
}
// NewEndpoints wraps the methods of the "cache" service with endpoints.
func NewEndpoints(s Service) *Endpoints {
return &Endpoints{
Get: NewGetEndpoint(s),
Set: NewSetEndpoint(s),
}
}
// Use applies the given middleware to all the "cache" service endpoints.
func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) {
e.Get = m(e.Get)
e.Set = m(e.Set)
}
// NewGetEndpoint returns an endpoint function that calls the method "Get" of
......@@ -38,3 +41,12 @@ func NewGetEndpoint(s Service) goa.Endpoint {
return s.Get(ctx, p)
}
}
// NewSetEndpoint returns an endpoint function that calls the method "Set" of
// service "cache".
func NewSetEndpoint(s Service) goa.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
p := req.(*CacheSetRequest)
return nil, s.Set(ctx, p)
}
}
......@@ -13,9 +13,10 @@ import (
// Cache service allows storing and retrieving data from distributed cache.
type Service interface {
// Get value from the cache. The result is a sequence of bytes which the client
// must decode.
Get(context.Context, *CacheGetRequest) (res []byte, err error)
// Get JSON value from the cache.
Get(context.Context, *CacheGetRequest) (res interface{}, err error)
// Set a JSON value in the cache.
Set(context.Context, *CacheSetRequest) (err error)
}
// ServiceName is the name of the service as defined in the design. This is the
......@@ -26,7 +27,7 @@ const ServiceName = "cache"
// MethodNames lists the service method names as defined in the design. These
// are the same values that are set in the endpoint request contexts under the
// MethodKey key.
var MethodNames = [1]string{"Get"}
var MethodNames = [2]string{"Get", "Set"}
// CacheGetRequest is the payload type of the cache service Get method.
type CacheGetRequest struct {
......@@ -34,3 +35,11 @@ type CacheGetRequest struct {
Namespace string
Scope string
}
// CacheSetRequest is the payload type of the cache service Set method.
type CacheSetRequest struct {
Data interface{}
Key string
Namespace string
Scope string
}
......@@ -8,6 +8,9 @@
package client
import (
"encoding/json"
"fmt"
cache "code.vereign.com/gaiax/tsa/cache/gen/cache"
)
......@@ -32,3 +35,36 @@ func BuildGetPayload(cacheGetKey string, cacheGetNamespace string, cacheGetScope
return v, nil
}
// BuildSetPayload builds the payload for the cache Set endpoint from CLI flags.
func BuildSetPayload(cacheSetBody string, cacheSetKey string, cacheSetNamespace string, cacheSetScope string) (*cache.CacheSetRequest, error) {
var err error
var body interface{}
{
err = json.Unmarshal([]byte(cacheSetBody), &body)
if err != nil {
return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Quasi ut.\"")
}
}
var key string
{
key = cacheSetKey
}
var namespace string
{
namespace = cacheSetNamespace
}
var scope string
{
scope = cacheSetScope
}
v := body
res := &cache.CacheSetRequest{
Data: v,
}
res.Key = key
res.Namespace = namespace
res.Scope = scope
return res, nil
}
......@@ -20,6 +20,9 @@ type Client struct {
// Get Doer is the HTTP client used to make requests to the Get endpoint.
GetDoer goahttp.Doer
// Set Doer is the HTTP client used to make requests to the Set endpoint.
SetDoer goahttp.Doer
// RestoreResponseBody controls whether the response bodies are reset after
// decoding so they can be read again.
RestoreResponseBody bool
......@@ -41,6 +44,7 @@ func NewClient(
) *Client {
return &Client{
GetDoer: doer,
SetDoer: doer,
RestoreResponseBody: restoreBody,
scheme: scheme,
host: host,
......@@ -72,3 +76,27 @@ func (c *Client) Get() goa.Endpoint {
return decodeResponse(resp)
}
}
// Set returns an endpoint that makes HTTP requests to the cache service Set
// server.
func (c *Client) Set() goa.Endpoint {
var (
encodeRequest = EncodeSetRequest(c.encoder)
decodeResponse = DecodeSetResponse(c.decoder, c.RestoreResponseBody)
)
return func(ctx context.Context, v interface{}) (interface{}, error) {
req, err := c.BuildSetRequest(ctx, v)
if err != nil {
return nil, err
}
err = encodeRequest(req, v)
if err != nil {
return nil, err
}
resp, err := c.SetDoer.Do(req)
if err != nil {
return nil, goahttp.ErrRequestError("cache", "Set", err)
}
return decodeResponse(resp)
}
}
......@@ -77,7 +77,7 @@ func DecodeGetResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody
switch resp.StatusCode {
case http.StatusOK:
var (
body []byte
body interface{}
err error
)
err = decoder(resp).Decode(&body)
......@@ -91,3 +91,73 @@ func DecodeGetResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody
}
}
}
// BuildSetRequest instantiates a HTTP request object with method and path set
// to call the "cache" service "Set" endpoint
func (c *Client) BuildSetRequest(ctx context.Context, v interface{}) (*http.Request, error) {
u := &url.URL{Scheme: c.scheme, Host: c.host, Path: SetCachePath()}
req, err := http.NewRequest("POST", u.String(), nil)
if err != nil {
return nil, goahttp.ErrInvalidURL("cache", "Set", u.String(), err)
}
if ctx != nil {
req = req.WithContext(ctx)
}
return req, nil
}
// EncodeSetRequest returns an encoder for requests sent to the cache Set
// server.
func EncodeSetRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error {
return func(req *http.Request, v interface{}) error {
p, ok := v.(*cache.CacheSetRequest)
if !ok {
return goahttp.ErrInvalidType("cache", "Set", "*cache.CacheSetRequest", v)
}
{
head := p.Key
req.Header.Set("x-cache-key", head)
}
{
head := p.Namespace
req.Header.Set("x-cache-namespace", head)
}
{
head := p.Scope
req.Header.Set("x-cache-scope", head)
}
body := p.Data
if err := encoder(req).Encode(&body); err != nil {
return goahttp.ErrEncodingError("cache", "Set", err)
}
return nil
}
}
// DecodeSetResponse returns a decoder for responses returned by the cache Set
// endpoint. restoreBody controls whether the response body should be restored
// after having been read.
func DecodeSetResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) {
return func(resp *http.Response) (interface{}, error) {
if restoreBody {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
defer func() {
resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
}()
} else {
defer resp.Body.Close()
}
switch resp.StatusCode {
case http.StatusCreated:
return nil, nil
default:
body, _ := ioutil.ReadAll(resp.Body)
return nil, goahttp.ErrInvalidResponse("cache", "Set", resp.StatusCode, string(body))
}
}
}
......@@ -11,3 +11,8 @@ package client
func GetCachePath() string {
return "/v1/cache"
}
// SetCachePath returns the URL path to the cache service Set HTTP endpoint.
func SetCachePath() string {
return "/v1/cache"
}
......@@ -9,6 +9,7 @@ package server
import (
"context"
"io"
"net/http"
goahttp "goa.design/goa/v3/http"
......@@ -19,7 +20,8 @@ import (
// endpoint.
func EncodeGetResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error {
return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
res, _ := v.([]byte)
res, _ := v.(interface{})
ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "application/json")
enc := encoder(ctx, w)
body := res
w.WriteHeader(http.StatusOK)
......@@ -57,3 +59,54 @@ func DecodeGetRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Dec
return payload, nil
}
}
// EncodeSetResponse returns an encoder for responses returned by the cache Set
// endpoint.
func EncodeSetResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error {
return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
w.WriteHeader(http.StatusCreated)
return nil
}
}
// DecodeSetRequest returns a decoder for requests sent to the cache Set
// endpoint.
func DecodeSetRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) {
return func(r *http.Request) (interface{}, error) {
var (
body interface{}
err error
)
err = decoder(r).Decode(&body)
if err != nil {
if err == io.EOF {
return nil, goa.MissingPayloadError()
}
return nil, goa.DecodePayloadError(err.Error())
}
var (
key string
namespace string
scope string
)
key = r.Header.Get("x-cache-key")
if key == "" {
err = goa.MergeErrors(err, goa.MissingFieldError("x-cache-key", "header"))
}
namespace = r.Header.Get("x-cache-namespace")
if namespace == "" {
err = goa.MergeErrors(err, goa.MissingFieldError("x-cache-namespace", "header"))
}
scope = r.Header.Get("x-cache-scope")
if scope == "" {
err = goa.MergeErrors(err, goa.MissingFieldError("x-cache-scope", "header"))
}
if err != nil {
return nil, err
}
payload := NewSetCacheSetRequest(body, key, namespace, scope)
return payload, nil
}
}
......@@ -11,3 +11,8 @@ package server
func GetCachePath() string {
return "/v1/cache"
}
// SetCachePath returns the URL path to the cache service Set HTTP endpoint.
func SetCachePath() string {
return "/v1/cache"
}
......@@ -20,6 +20,7 @@ import (
type Server struct {
Mounts []*MountPoint
Get http.Handler
Set http.Handler
}
// ErrorNamer is an interface implemented by generated error structs that
......@@ -56,8 +57,10 @@ func New(
return &Server{
Mounts: []*MountPoint{
{"Get", "GET", "/v1/cache"},
{"Set", "POST", "/v1/cache"},
},
Get: NewGetHandler(e.Get, mux, decoder, encoder, errhandler, formatter),
Set: NewSetHandler(e.Set, mux, decoder, encoder, errhandler, formatter),
}
}
......@@ -67,11 +70,13 @@ func (s *Server) Service() string { return "cache" }
// Use wraps the server handlers with the given middleware.
func (s *Server) Use(m func(http.Handler) http.Handler) {
s.Get = m(s.Get)
s.Set = m(s.Set)
}
// Mount configures the mux to serve the cache endpoints.
func Mount(mux goahttp.Muxer, h *Server) {
MountGetHandler(mux, h.Get)
MountSetHandler(mux, h.Set)
}
// Mount configures the mux to serve the cache endpoints.
......@@ -129,3 +134,54 @@ func NewGetHandler(
}
})
}
// MountSetHandler configures the mux to serve the "cache" service "Set"
// endpoint.
func MountSetHandler(mux goahttp.Muxer, h http.Handler) {
f, ok := h.(http.HandlerFunc)
if !ok {
f = func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r)
}
}
mux.Handle("POST", "/v1/cache", f)
}
// NewSetHandler creates a HTTP handler which loads the HTTP request and calls
// the "cache" service "Set" endpoint.
func NewSetHandler(
endpoint goa.Endpoint,
mux goahttp.Muxer,
decoder func(*http.Request) goahttp.Decoder,
encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
errhandler func(context.Context, http.ResponseWriter, error),
formatter func(err error) goahttp.Statuser,
) http.Handler {
var (
decodeRequest = DecodeSetRequest(mux, decoder)
encodeResponse = EncodeSetResponse(encoder)
encodeError = goahttp.ErrorEncoder(encoder, formatter)
)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept"))
ctx = context.WithValue(ctx, goa.MethodKey, "Set")
ctx = context.WithValue(ctx, goa.ServiceKey, "cache")
payload, err := decodeRequest(r)
if err != nil {
if err := encodeError(ctx, w, err); err != nil {
errhandler(ctx, w, err)
}
return
}
res, err := endpoint(ctx, payload)
if err != nil {
if err := encodeError(ctx, w, err); err != nil {
errhandler(ctx, w, err)
}
return
}
if err := encodeResponse(ctx, w, res); err != nil {
errhandler(ctx, w, err)
}
})
}
......@@ -20,3 +20,16 @@ func NewGetCacheGetRequest(key string, namespace string, scope string) *cache.Ca
return v
}
// NewSetCacheSetRequest builds a cache service Set endpoint payload.
func NewSetCacheSetRequest(body interface{}, key string, namespace string, scope string) *cache.CacheSetRequest {
v := body
res := &cache.CacheSetRequest{
Data: v,
}
res.Key = key
res.Namespace = namespace
res.Scope = scope
return res
}
......@@ -25,14 +25,14 @@ import (
//
func UsageCommands() string {
return `health (liveness|readiness)
cache get
cache (get|set)
`
}
// UsageExamples produces an example of a valid invocation of the CLI tool.
func UsageExamples() string {
return os.Args[0] + ` health liveness` + "\n" +
os.Args[0] + ` cache get --key "Officiis fuga architecto cum." --namespace "Sint adipisci." --scope "Debitis id reprehenderit incidunt necessitatibus assumenda."` + "\n" +
os.Args[0] + ` cache get --key "Suscipit sed consequatur rerum occaecati in veritatis." --namespace "Repudiandae eos consequatur sint dolorum occaecati." --scope "Voluptatum modi tenetur tempore quia est ratione."` + "\n" +
""
}
......@@ -58,6 +58,12 @@ func ParseEndpoint(
cacheGetKeyFlag = cacheGetFlags.String("key", "REQUIRED", "")
cacheGetNamespaceFlag = cacheGetFlags.String("namespace", "REQUIRED", "")
cacheGetScopeFlag = cacheGetFlags.String("scope", "REQUIRED", "")
cacheSetFlags = flag.NewFlagSet("set", flag.ExitOnError)
cacheSetBodyFlag = cacheSetFlags.String("body", "REQUIRED", "")
cacheSetKeyFlag = cacheSetFlags.String("key", "REQUIRED", "")
cacheSetNamespaceFlag = cacheSetFlags.String("namespace", "REQUIRED", "")
cacheSetScopeFlag = cacheSetFlags.String("scope", "REQUIRED", "")
)
healthFlags.Usage = healthUsage
healthLivenessFlags.Usage = healthLivenessUsage
......@@ -65,6 +71,7 @@ func ParseEndpoint(
cacheFlags.Usage = cacheUsage
cacheGetFlags.Usage = cacheGetUsage
cacheSetFlags.Usage = cacheSetUsage
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
return nil, nil, err
......@@ -115,6 +122,9 @@ func ParseEndpoint(
case "get":
epf = cacheGetFlags
case "set":
epf = cacheSetFlags
}
}
......@@ -153,6 +163,9 @@ func ParseEndpoint(
case "get":
endpoint = c.Get()
data, err = cachec.BuildGetPayload(*cacheGetKeyFlag, *cacheGetNamespaceFlag, *cacheGetScopeFlag)
case "set":
endpoint = c.Set()
data, err = cachec.BuildSetPayload(*cacheSetBodyFlag, *cacheSetKeyFlag, *cacheSetNamespaceFlag, *cacheSetScopeFlag)
}
}
}
......@@ -204,7 +217,8 @@ Usage:
%[1]s [globalflags] cache COMMAND [flags]
COMMAND:
get: Get value from the cache. The result is a sequence of bytes which the client must decode.
get: Get JSON value from the cache.
set: Set a JSON value in the cache.
Additional help:
%[1]s cache COMMAND --help
......@@ -213,12 +227,26 @@ Additional help:
func cacheGetUsage() {
fmt.Fprintf(os.Stderr, `%[1]s [flags] cache get -key STRING -namespace STRING -scope STRING
Get value from the cache. The result is a sequence of bytes which the client must decode.
Get JSON value from the cache.
-key STRING:
-namespace STRING:
-scope STRING:
Example:
%[1]s cache get --key "Suscipit sed consequatur rerum occaecati in veritatis." --namespace "Repudiandae eos consequatur sint dolorum occaecati." --scope "Voluptatum modi tenetur tempore quia est ratione."
`, os.Args[0])
}
func cacheSetUsage() {
fmt.Fprintf(os.Stderr, `%[1]s [flags] cache set -body JSON -key STRING -namespace STRING -scope STRING
Set a JSON value in the cache.
-body JSON:
-key STRING:
-namespace STRING:
-scope STRING:
Example:
%[1]s cache get --key "Officiis fuga architecto cum." --namespace "Sint adipisci." --scope "Debitis id reprehenderit incidunt necessitatibus assumenda."
%[1]s cache set --body "Quasi ut." --key "Quasi perspiciatis." --namespace "Accusantium animi non alias." --scope "Esse inventore ullam placeat aut."
`, os.Args[0])
}
{"swagger":"2.0","info":{"title":"Cache Service","description":"The cache service exposes interface for working with Redis.","version":""},"host":"localhost:8083","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/cache":{"get":{"tags":["cache"],"summary":"Get cache","description":"Get value from the cache. The result is a sequence of bytes which the client must decode.","operationId":"cache#Get","parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","required":true,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"byte"}}},"schemes":["http"]}}}}
\ No newline at end of file
{"swagger":"2.0","info":{"title":"Cache Service","description":"The cache service exposes interface for working with Redis.","version":""},"host":"localhost:8083","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/cache":{"get":{"tags":["cache"],"summary":"Get cache","description":"Get JSON value from the cache.","operationId":"cache#Get","produces":["application/json"],"parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","required":true,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]},"post":{"tags":["cache"],"summary":"Set cache","description":"Set a JSON value in the cache.","operationId":"cache#Set","parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","required":true,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","required":true,"type":"string"},{"name":"any","in":"body","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"201":{"description":"Created response."}},"schemes":["http"]}}}}
\ No newline at end of file
......@@ -40,9 +40,10 @@ paths:
tags:
- cache
summary: Get cache
description: Get value from the cache. The result is a sequence of bytes which
the client must decode.
description: Get JSON value from the cache.
operationId: cache#Get
produces:
- application/json
parameters:
- name: x-cache-key
in: header
......@@ -64,6 +65,39 @@ paths:
description: OK response.
schema:
type: string
format: byte
format: binary
schemes:
- http
post:
tags:
- cache
summary: Set cache
description: Set a JSON value in the cache.
operationId: cache#Set
parameters:
- name: x-cache-key
in: header
description: Cache entry key
required: true
type: string
- name: x-cache-namespace
in: header
description: Cache entry namespace
required: true
type: string
- name: x-cache-scope
in: header
description: Cache entry scope
required: true
type: string
- name: any
in: body
required: true
schema:
type: string
format: binary
responses:
"201":
description: Created response.
schemes:
- http
{"openapi":"3.0.3","info":{"title":"Cache Service","description":"The cache service exposes interface for working with Redis.","version":"1.0"},"servers":[{"url":"http://localhost:8083","description":"Cache Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/cache":{"get":{"tags":["cache"],"summary":"Get cache","description":"Get value from the cache. The result is a sequence of bytes which the client must decode.","operationId":"cache#Get","parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry key","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry namespace","example":"Login"},"example":"Login"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry scope","example":"administration"},"example":"administration"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"UmVwdWRpYW5kYWUgZW9zIGNvbnNlcXVhdHVyIHNpbnQgZG9sb3J1bSBvY2NhZWNhdGku","format":"binary"},"example":"Vm9sdXB0YXR1bSBtb2RpIHRlbmV0dXIgdGVtcG9yZSBxdWlhIGVzdCByYXRpb25lLg=="}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"cache","description":"Cache service allows storing and retrieving data from distributed cache."}]}
\ No newline at end of file
{"openapi":"3.0.3","info":{"title":"Cache Service","description":"The cache service exposes interface for working with Redis.","version":"1.0"},"servers":[{"url":"http://localhost:8083","description":"Cache Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/cache":{"get":{"tags":["cache"],"summary":"Get cache","description":"Get JSON value from the cache.","operationId":"cache#Get","parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry key","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry namespace","example":"Login"},"example":"Login"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry scope","example":"administration"},"example":"administration"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Qui iusto enim est dolores dolorem et.","format":"binary"},"example":"Quisquam ab dolores distinctio quis."}}}}},"post":{"tags":["cache"],"summary":"Set cache","description":"Set a JSON value in the cache.","operationId":"cache#Set","parameters":[{"name":"x-cache-key","in":"header","description":"Cache entry key","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry key","example":"did:web:example.com"},"example":"did:web:example.com"},{"name":"x-cache-namespace","in":"header","description":"Cache entry namespace","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry namespace","example":"Login"},"example":"Login"},{"name":"x-cache-scope","in":"header","description":"Cache entry scope","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"Cache entry scope","example":"administration"},"example":"administration"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","example":"Et illum fugiat ut.","format":"binary"},"example":"Optio aliquam error nam."}}},"responses":{"201":{"description":"Created response."}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"cache","description":"Cache service allows storing and retrieving data from distributed cache."}]}
\ No newline at end of file
......@@ -30,8 +30,7 @@ paths:
tags:
- cache
summary: Get cache
description: Get value from the cache. The result is a sequence of bytes which
the client must decode.
description: Get JSON value from the cache.
operationId: cache#Get
parameters:
- name: x-cache-key
......@@ -71,109 +70,58 @@ paths:
application/json:
schema:
type: string
example:
- 82
- 101
- 112
- 117
- 100
- 105
- 97
- 110
- 100
- 97
- 101
- 32
- 101
- 111
- 115
- 32
- 99
- 111
- 110
- 115
- 101
- 113
- 117
- 97
- 116
- 117
- 114
- 32
- 115
- 105
- 110
- 116
- 32
- 100
- 111
- 108
- 111
- 114
- 117
- 109
- 32
- 111
- 99
- 99
- 97
- 101
- 99
- 97
- 116
- 105
- 46
example: Qui iusto enim est dolores dolorem et.
format: binary
example:
- 86
- 111
- 108
- 117
- 112
- 116
- 97
- 116
- 117
- 109
- 32
- 109
- 111
- 100
- 105
- 32
- 116
- 101
- 110
- 101
- 116
- 117
- 114
- 32
- 116
- 101
- 109
- 112
- 111
- 114
- 101
- 32
- 113
- 117
- 105
- 97
- 32
- 101
- 115
- 116
- 32
- 114
- 97
- 116
- 105
- 111
- 110
- 101
- 46
example: Quisquam ab dolores distinctio quis.
post:
tags:
- cache
summary: Set cache
description: Set a JSON value in the cache.
operationId: cache#Set
parameters:
- name: x-cache-key
in: header
description: Cache entry key
allowEmptyValue: true
required: true
schema:
type: string
description: Cache entry key
example: did:web:example.com
example: did:web:example.com
- name: x-cache-namespace
in: header
description: Cache entry namespace
allowEmptyValue: true
required: true
schema:
type: string
description: Cache entry namespace
example: Login
example: Login
- name: x-cache-scope
in: header
description: Cache entry scope
allowEmptyValue: true
required: true
schema:
type: string
description: Cache entry scope
example: administration
example: administration
requestBody:
required: true
content:
application/json:
schema:
type: string
example: Et illum fugiat ut.
format: binary
example: Optio aliquam error nam.
responses:
"201":
description: Created response.
components: {}
tags:
- name: health
......
......@@ -41,3 +41,11 @@ func (c *Client) Get(ctx context.Context, key string) ([]byte, error) {
}
return []byte(result.Val()), nil
}
func (c *Client) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error {
if ttl == 0 {
ttl = c.defaultTTL
}
return c.rdb.Set(ctx, key, value, ttl).Err()
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment