mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Add scope support
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,14 @@ type HTTPRequestLog struct {
|
||||
Response *HTTPResponseLog `json:"response"`
|
||||
}
|
||||
|
||||
type HTTPRequestLogFilter struct {
|
||||
OnlyInScope bool `json:"onlyInScope"`
|
||||
}
|
||||
|
||||
type HTTPRequestLogFilterInput struct {
|
||||
OnlyInScope *bool `json:"onlyInScope"`
|
||||
}
|
||||
|
||||
type HTTPResponseLog struct {
|
||||
RequestID int64 `json:"requestId"`
|
||||
Proto string `json:"proto"`
|
||||
@ -47,6 +55,28 @@ type Project struct {
|
||||
IsActive bool `json:"isActive"`
|
||||
}
|
||||
|
||||
type ScopeHeader struct {
|
||||
Key *string `json:"key"`
|
||||
Value *string `json:"value"`
|
||||
}
|
||||
|
||||
type ScopeHeaderInput struct {
|
||||
Key *string `json:"key"`
|
||||
Value *string `json:"value"`
|
||||
}
|
||||
|
||||
type ScopeRule struct {
|
||||
URL *string `json:"url"`
|
||||
Header *ScopeHeader `json:"header"`
|
||||
Body *string `json:"body"`
|
||||
}
|
||||
|
||||
type ScopeRuleInput struct {
|
||||
URL *string `json:"url"`
|
||||
Header *ScopeHeaderInput `json:"header"`
|
||||
Body *string `json:"body"`
|
||||
}
|
||||
|
||||
type HTTPMethod string
|
||||
|
||||
const (
|
||||
|
@ -5,17 +5,20 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/dstotijn/hetty/pkg/proj"
|
||||
"github.com/dstotijn/hetty/pkg/reqlog"
|
||||
"github.com/dstotijn/hetty/pkg/scope"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type Resolver struct {
|
||||
RequestLogService *reqlog.Service
|
||||
ProjectService *proj.Service
|
||||
ScopeService *scope.Scope
|
||||
}
|
||||
|
||||
type queryResolver struct{ *Resolver }
|
||||
@ -25,9 +28,8 @@ func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
|
||||
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
func (r *queryResolver) HTTPRequestLogs(ctx context.Context) ([]HTTPRequestLog, error) {
|
||||
opts := reqlog.FindRequestsOptions{OmitOutOfScope: false}
|
||||
reqs, err := r.RequestLogService.FindRequests(ctx, opts)
|
||||
if err == reqlog.ErrNoProject {
|
||||
reqs, err := r.RequestLogService.FindRequests(ctx)
|
||||
if err == proj.ErrNoProject {
|
||||
return nil, &gqlerror.Error{
|
||||
Path: graphql.GetPath(ctx),
|
||||
Message: "No active project.",
|
||||
@ -133,7 +135,7 @@ func parseRequestLog(req reqlog.Request) (HTTPRequestLog, error) {
|
||||
}
|
||||
|
||||
func (r *mutationResolver) OpenProject(ctx context.Context, name string) (*Project, error) {
|
||||
p, err := r.ProjectService.Open(name)
|
||||
p, err := r.ProjectService.Open(ctx, name)
|
||||
if err == proj.ErrInvalidName {
|
||||
return nil, gqlerror.Errorf("Project name must only contain alphanumeric or space chars.")
|
||||
}
|
||||
@ -178,6 +180,19 @@ func (r *queryResolver) Projects(ctx context.Context) ([]Project, error) {
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Scope(ctx context.Context) ([]ScopeRule, error) {
|
||||
rules := r.ScopeService.Rules()
|
||||
return scopeToScopeRules(rules), nil
|
||||
}
|
||||
|
||||
func regexpToStringPtr(r *regexp.Regexp) *string {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
s := r.String()
|
||||
return &s
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CloseProject(ctx context.Context) (*CloseProjectResult, error) {
|
||||
if err := r.ProjectService.Close(); err != nil {
|
||||
return nil, fmt.Errorf("could not close project: %v", err)
|
||||
@ -193,3 +208,107 @@ func (r *mutationResolver) DeleteProject(ctx context.Context, name string) (*Del
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SetScope(ctx context.Context, input []ScopeRuleInput) ([]ScopeRule, error) {
|
||||
rules := make([]scope.Rule, len(input))
|
||||
for i, rule := range input {
|
||||
u, err := stringPtrToRegexp(rule.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid URL in scope rule: %v", err)
|
||||
}
|
||||
var headerKey, headerValue *regexp.Regexp
|
||||
if rule.Header != nil {
|
||||
headerKey, err = stringPtrToRegexp(rule.Header.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid header key in scope rule: %v", err)
|
||||
}
|
||||
headerValue, err = stringPtrToRegexp(rule.Header.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid header value in scope rule: %v", err)
|
||||
}
|
||||
}
|
||||
body, err := stringPtrToRegexp(rule.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid body in scope rule: %v", err)
|
||||
}
|
||||
rules[i] = scope.Rule{
|
||||
URL: u,
|
||||
Header: scope.Header{
|
||||
Key: headerKey,
|
||||
Value: headerValue,
|
||||
},
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.ScopeService.SetRules(ctx, rules); err != nil {
|
||||
return nil, fmt.Errorf("could not set scope: %v", err)
|
||||
}
|
||||
|
||||
return scopeToScopeRules(rules), nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) HTTPRequestLogFilter(ctx context.Context) (*HTTPRequestLogFilter, error) {
|
||||
return findReqFilterToHTTPReqLogFilter(r.RequestLogService.FindReqsFilter), nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SetHTTPRequestLogFilter(
|
||||
ctx context.Context,
|
||||
input *HTTPRequestLogFilterInput,
|
||||
) (*HTTPRequestLogFilter, error) {
|
||||
filter := findRequestsFilterFromInput(input)
|
||||
if err := r.RequestLogService.SetRequestLogFilter(ctx, filter); err != nil {
|
||||
return nil, fmt.Errorf("could not set request log filter: %v", err)
|
||||
}
|
||||
|
||||
empty := reqlog.FindRequestsFilter{}
|
||||
if filter == empty {
|
||||
return nil, nil
|
||||
}
|
||||
return findReqFilterToHTTPReqLogFilter(filter), nil
|
||||
}
|
||||
|
||||
func stringPtrToRegexp(s *string) (*regexp.Regexp, error) {
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return regexp.Compile(*s)
|
||||
}
|
||||
|
||||
func scopeToScopeRules(rules []scope.Rule) []ScopeRule {
|
||||
scopeRules := make([]ScopeRule, len(rules))
|
||||
for i, rule := range rules {
|
||||
scopeRules[i].URL = regexpToStringPtr(rule.URL)
|
||||
if rule.Header.Key != nil || rule.Header.Value != nil {
|
||||
scopeRules[i].Header = &ScopeHeader{
|
||||
Key: regexpToStringPtr(rule.Header.Key),
|
||||
Value: regexpToStringPtr(rule.Header.Value),
|
||||
}
|
||||
}
|
||||
scopeRules[i].Body = regexpToStringPtr(rule.Body)
|
||||
}
|
||||
return scopeRules
|
||||
}
|
||||
|
||||
func findRequestsFilterFromInput(input *HTTPRequestLogFilterInput) (filter reqlog.FindRequestsFilter) {
|
||||
if input == nil {
|
||||
return
|
||||
}
|
||||
if input.OnlyInScope != nil {
|
||||
filter.OnlyInScope = *input.OnlyInScope
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func findReqFilterToHTTPReqLogFilter(findReqFilter reqlog.FindRequestsFilter) *HTTPRequestLogFilter {
|
||||
empty := reqlog.FindRequestsFilter{}
|
||||
if findReqFilter == empty {
|
||||
return nil
|
||||
}
|
||||
httpReqLogFilter := &HTTPRequestLogFilter{
|
||||
OnlyInScope: findReqFilter.OnlyInScope,
|
||||
}
|
||||
|
||||
return httpReqLogFilter
|
||||
}
|
||||
|
@ -28,6 +28,28 @@ type Project {
|
||||
isActive: Boolean!
|
||||
}
|
||||
|
||||
type ScopeRule {
|
||||
url: Regexp
|
||||
header: ScopeHeader
|
||||
body: Regexp
|
||||
}
|
||||
|
||||
input ScopeRuleInput {
|
||||
url: Regexp
|
||||
header: ScopeHeaderInput
|
||||
body: Regexp
|
||||
}
|
||||
|
||||
type ScopeHeader {
|
||||
key: Regexp
|
||||
value: Regexp
|
||||
}
|
||||
|
||||
input ScopeHeaderInput {
|
||||
key: Regexp
|
||||
value: Regexp
|
||||
}
|
||||
|
||||
type CloseProjectResult {
|
||||
success: Boolean!
|
||||
}
|
||||
@ -36,17 +58,31 @@ type DeleteProjectResult {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
input HttpRequestLogFilterInput {
|
||||
onlyInScope: Boolean
|
||||
}
|
||||
|
||||
type HttpRequestLogFilter {
|
||||
onlyInScope: Boolean!
|
||||
}
|
||||
|
||||
type Query {
|
||||
httpRequestLog(id: ID!): HttpRequestLog
|
||||
httpRequestLogs: [HttpRequestLog!]!
|
||||
httpRequestLogFilter: HttpRequestLogFilter
|
||||
activeProject: Project
|
||||
projects: [Project!]!
|
||||
scope: [ScopeRule!]!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
openProject(name: String!): Project
|
||||
closeProject: CloseProjectResult!
|
||||
deleteProject(name: String!): DeleteProjectResult!
|
||||
setScope(scope: [ScopeRuleInput!]!): [ScopeRule!]!
|
||||
setHttpRequestLogFilter(
|
||||
filter: HttpRequestLogFilterInput
|
||||
): HttpRequestLogFilter
|
||||
}
|
||||
|
||||
enum HttpMethod {
|
||||
@ -62,3 +98,4 @@ enum HttpMethod {
|
||||
}
|
||||
|
||||
scalar Time
|
||||
scalar Regexp
|
||||
|
Reference in New Issue
Block a user