graphql.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package v1
  11. import (
  12. "encoding/json"
  13. "fmt"
  14. "net/http"
  15. "devt.de/krotik/common/stringutil"
  16. "devt.de/krotik/eliasdb/api"
  17. "devt.de/krotik/eliasdb/graphql"
  18. )
  19. /*
  20. EndpointGraphQL is the GraphQL endpoint URL (rooted). Handles everything under graphql/...
  21. */
  22. const EndpointGraphQL = api.APIRoot + APIv1 + "/graphql/"
  23. /*
  24. GraphQLEndpointInst creates a new endpoint handler.
  25. */
  26. func GraphQLEndpointInst() api.RestEndpointHandler {
  27. return &graphQLEndpoint{}
  28. }
  29. /*
  30. Handler object for GraphQL operations.
  31. */
  32. type graphQLEndpoint struct {
  33. *api.DefaultEndpointHandler
  34. }
  35. /*
  36. HandlePOST handles GraphQL queries.
  37. */
  38. func (e *graphQLEndpoint) HandlePOST(w http.ResponseWriter, r *http.Request, resources []string) {
  39. dec := json.NewDecoder(r.Body)
  40. data := make(map[string]interface{})
  41. if err := dec.Decode(&data); err != nil {
  42. http.Error(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
  43. return
  44. }
  45. partData, ok := data["partition"]
  46. if !ok && len(resources) > 0 {
  47. partData = resources[0]
  48. ok = true
  49. }
  50. if !ok || partData == "" {
  51. http.Error(w, "Need a partition", http.StatusBadRequest)
  52. return
  53. }
  54. part := fmt.Sprint(partData)
  55. if _, ok := data["variables"]; !ok {
  56. data["variables"] = nil
  57. }
  58. if _, ok := data["operationName"]; !ok {
  59. data["operationName"] = nil
  60. }
  61. res, err := graphql.RunQuery(stringutil.CreateDisplayString(part)+" query",
  62. part, data, api.GM, nil, false)
  63. if err != nil {
  64. http.Error(w, err.Error(), http.StatusBadRequest)
  65. return
  66. }
  67. w.Header().Set("content-type", "application/json; charset=utf-8")
  68. json.NewEncoder(w).Encode(res)
  69. }
  70. /*
  71. SwaggerDefs is used to describe the endpoint in swagger.
  72. */
  73. func (e *graphQLEndpoint) SwaggerDefs(s map[string]interface{}) {
  74. s["paths"].(map[string]interface{})["/v1/graphql"] = map[string]interface{}{
  75. "post": map[string]interface{}{
  76. "summary": "GraphQL interface.",
  77. "description": "The GraphQL interface can be used to query and modify data.",
  78. "consumes": []string{
  79. "application/json",
  80. },
  81. "produces": []string{
  82. "text/plain",
  83. "application/json",
  84. },
  85. "parameters": []map[string]interface{}{
  86. map[string]interface{}{
  87. "name": "partition",
  88. "in": "path",
  89. "description": "Partition to query.",
  90. "required": false,
  91. "type": "string",
  92. },
  93. map[string]interface{}{
  94. "name": "partition",
  95. "in": "body",
  96. "description": "Partition to query.",
  97. "required": false,
  98. "type": "string",
  99. },
  100. map[string]interface{}{
  101. "name": "operationName",
  102. "in": "body",
  103. "description": "GraphQL query operation name.",
  104. "required": false,
  105. },
  106. map[string]interface{}{
  107. "name": "query",
  108. "in": "body",
  109. "description": "GraphQL query.",
  110. "required": true,
  111. },
  112. map[string]interface{}{
  113. "name": "variables",
  114. "in": "body",
  115. "description": "GraphQL query variable values.",
  116. "required": false,
  117. },
  118. },
  119. "responses": map[string]interface{}{
  120. "200": map[string]interface{}{
  121. "description": "The operation was successful.",
  122. },
  123. "default": map[string]interface{}{
  124. "description": "Error response",
  125. "schema": map[string]interface{}{
  126. "$ref": "#/definitions/Error",
  127. },
  128. },
  129. },
  130. },
  131. }
  132. }