-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
596012e
commit 7c3fe36
Showing
5 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package api | ||
|
||
import ( | ||
"database/sql" | ||
"log" | ||
"net/http" | ||
|
||
"go-pagination/repository" | ||
"go-pagination/service" | ||
) | ||
|
||
func Start(testDB *sql.DB) error { | ||
bookRepo := repository.NewBookRepository(testDB) | ||
bookService := service.NewBookService(bookRepo) | ||
|
||
handlerGQL, err := NewHandlerGQL(bookService) | ||
if err != nil { | ||
log.Fatalf("expected handler gql error nil, got %v", err) | ||
} | ||
|
||
mux := http.NewServeMux() | ||
mux.HandleFunc("GET /api/graphql/", handlerGQL.HandlerQueries) | ||
mux.HandleFunc("POST /api/graphql/", handlerGQL.HandlerMutations) | ||
|
||
return http.ListenAndServe(":3000", mux) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package api | ||
|
||
import ( | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
type Client struct { | ||
baseURL string | ||
apiKey string | ||
clientHTTP *http.Client | ||
} | ||
|
||
func NewClient(baseURL, apiKey string) *Client { | ||
return &Client{ | ||
baseURL: baseURL, | ||
apiKey: apiKey, | ||
clientHTTP: &http.Client{ | ||
Timeout: 3 * time.Second, | ||
}, | ||
} | ||
} | ||
|
||
func (c *Client) makeRequest(method, endpoint string, queries map[string]string, body io.Reader) (*http.Response, error) { | ||
u, err := c.getURL(endpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req, err := http.NewRequest(method, u, body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
q := req.URL.Query() | ||
|
||
for key, value := range queries { | ||
q.Add(key, value) | ||
} | ||
|
||
req.URL.RawQuery = q.Encode() | ||
|
||
return c.clientHTTP.Do(req) | ||
} | ||
|
||
func (c *Client) getURL(p string) (string, error) { | ||
return url.JoinPath(c.baseURL, p) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package api | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"io" | ||
"log" | ||
"net/http" | ||
|
||
"go-pagination/domain" | ||
"go-pagination/gql" | ||
|
||
"github.com/graphql-go/graphql" | ||
) | ||
|
||
const ( | ||
KeyQuery = "query" | ||
) | ||
|
||
type BodyGQL struct { | ||
Query string `json:"query"` | ||
Variables map[string]any `json:"variables"` | ||
Operation string `json:"operation"` | ||
} | ||
|
||
type HandlerGQL struct { | ||
schema graphql.Schema | ||
} | ||
|
||
func NewHandlerGQL(bookService domain.BookService) (*HandlerGQL, error) { | ||
schema, err := gql.NewSchema(bookService) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
h := &HandlerGQL{ | ||
schema: schema, | ||
} | ||
|
||
return h, nil | ||
} | ||
|
||
func (h *HandlerGQL) HandlerQueries(w http.ResponseWriter, r *http.Request) { | ||
var variables map[string]any | ||
var operation string | ||
var rootObject map[string]any | ||
|
||
q := r.URL.Query() | ||
query := q.Get(KeyQuery) | ||
|
||
params := graphql.Params{ | ||
Schema: h.schema, | ||
RequestString: query, | ||
// mutations | ||
VariableValues: variables, | ||
OperationName: operation, | ||
Context: r.Context(), | ||
RootObject: rootObject, | ||
} | ||
|
||
result := graphql.Do(params) | ||
|
||
var buffer bytes.Buffer | ||
|
||
err := json.NewEncoder(&buffer).Encode(result) | ||
if err != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
w.WriteHeader(http.StatusOK) | ||
w.Header().Add("Content-Type", "application/json") | ||
_, err = w.Write(buffer.Bytes()) | ||
if err != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
func (h *HandlerGQL) HandlerMutations(w http.ResponseWriter, r *http.Request) { | ||
var bGQL BodyGQL | ||
|
||
err := json.NewDecoder(r.Body).Decode(&bGQL) | ||
if err != nil { | ||
w.WriteHeader(http.StatusBadRequest) | ||
return | ||
} | ||
|
||
defer func() { | ||
err = r.Body.Close() | ||
if err != nil { | ||
log.Println("request body close error: ", err) | ||
} | ||
}() | ||
|
||
var rootObject map[string]any | ||
|
||
params := graphql.Params{ | ||
Schema: h.schema, | ||
RequestString: bGQL.Query, | ||
// mutations | ||
VariableValues: bGQL.Variables, | ||
OperationName: bGQL.Operation, | ||
Context: r.Context(), | ||
RootObject: rootObject, | ||
} | ||
|
||
result := graphql.Do(params) | ||
|
||
var buffer bytes.Buffer | ||
|
||
err = json.NewEncoder(&buffer).Encode(result) | ||
if err != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
w.WriteHeader(http.StatusOK) | ||
w.Header().Add("Content-Type", "application/json") | ||
_, err = io.Copy(w, &buffer) | ||
if err != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package api | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"io" | ||
"log" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"go-pagination/repository" | ||
"go-pagination/service" | ||
) | ||
|
||
func TestHandlerGQL(t *testing.T) { | ||
bookRepo := repository.NewBookRepository(testDB) | ||
bookService := service.NewBookService(bookRepo) | ||
|
||
handlerGQL, err := NewHandlerGQL(bookService) | ||
if err != nil { | ||
t.Fatalf("expected handler gql error nil, got %v", err) | ||
} | ||
|
||
mux := http.NewServeMux() | ||
mux.HandleFunc("GET /api/graphql/", handlerGQL.HandlerQueries) | ||
mux.HandleFunc("POST /api/graphql/", handlerGQL.HandlerMutations) | ||
|
||
server := httptest.NewServer(mux) | ||
|
||
const endpoint = "/api/graphql/" | ||
|
||
client := NewClient(server.URL, "") | ||
|
||
t.Run("test query book pagination", func(t *testing.T) { | ||
query := ` | ||
query { | ||
books(page: 1, perPage: 5) { | ||
nextPage | ||
page | ||
pages | ||
items { | ||
id | ||
title | ||
} | ||
} | ||
} | ||
` | ||
|
||
queries := map[string]string{ | ||
KeyQuery: query, | ||
} | ||
|
||
var resp *http.Response | ||
resp, err = client.makeRequest( | ||
http.MethodGet, | ||
endpoint, | ||
queries, | ||
nil, | ||
) | ||
if err != nil { | ||
t.Fatalf("expected http request error nil, got %v", err) | ||
} | ||
|
||
var buffer bytes.Buffer | ||
_, err = io.Copy(&buffer, resp.Body) | ||
if err != nil { | ||
t.Fatalf("expected response read error nil, got %v", err) | ||
} | ||
|
||
defer func() { | ||
err = resp.Body.Close() | ||
if err != nil { | ||
log.Println("response body close error: ", err) | ||
} | ||
}() | ||
|
||
s := buffer.String() | ||
if s != "" { | ||
log.Fatalf("response body: %s", s) | ||
} | ||
}) | ||
|
||
t.Run("test mutation create book", func(t *testing.T) { | ||
query := ` | ||
mutation CreateBook($book: InputBook!) { | ||
createBook(input: $book) { | ||
id | ||
title | ||
author | ||
createdAt | ||
updatedAt | ||
} | ||
} | ||
` | ||
|
||
book := map[string]any{ | ||
"title": "Go development", | ||
"author": "JamsMendez", | ||
} | ||
|
||
variables := map[string]any{ | ||
"book": book, | ||
} | ||
|
||
bodyGQL := BodyGQL{ | ||
Query: query, | ||
Variables: variables, | ||
Operation: "CreateBook", | ||
} | ||
|
||
var body bytes.Buffer | ||
|
||
err = json.NewEncoder(&body).Encode(bodyGQL) | ||
if err != nil { | ||
t.Fatalf("expected json encode error nil, got %v", err) | ||
} | ||
|
||
var queries map[string]string | ||
|
||
var resp *http.Response | ||
resp, err = client.makeRequest( | ||
http.MethodPost, | ||
endpoint, | ||
queries, | ||
&body, | ||
) | ||
if err != nil { | ||
t.Fatalf("expected http request error nil, got %v", err) | ||
} | ||
|
||
var buffer bytes.Buffer | ||
_, err = io.Copy(&buffer, resp.Body) | ||
if err != nil { | ||
t.Fatalf("expected response read error nil, got %v", err) | ||
} | ||
|
||
defer func() { | ||
err = resp.Body.Close() | ||
if err != nil { | ||
log.Println("response body close error: ", err) | ||
} | ||
}() | ||
|
||
s := buffer.String() | ||
if s != "" { | ||
log.Fatalf("response bodyGQL: %s", s) | ||
} | ||
}) | ||
} |
Oops, something went wrong.