graphql.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. graphqlRequestParam := map[string]interface{}{
  75. "name": "graphql_request",
  76. "in": "body",
  77. "description": "GraphQL request",
  78. "required": true,
  79. "schema": map[string]interface{}{
  80. "$ref": "#/definitions/GraphQLRequest",
  81. },
  82. }
  83. s["paths"].(map[string]interface{})["/v1/graphql/{partition}"] = map[string]interface{}{
  84. "post": map[string]interface{}{
  85. "summary": "GraphQL interface.",
  86. "description": "The GraphQL interface can be used to query and modify data.",
  87. "consumes": []string{
  88. "application/json",
  89. },
  90. "produces": []string{
  91. "text/plain",
  92. "application/json",
  93. },
  94. "parameters": []map[string]interface{}{
  95. {
  96. "name": "partition",
  97. "in": "path",
  98. "description": "Partition to query.",
  99. "required": true,
  100. "type": "string",
  101. },
  102. graphqlRequestParam,
  103. },
  104. "responses": map[string]interface{}{
  105. "200": map[string]interface{}{
  106. "description": "The operation was successful.",
  107. },
  108. "default": map[string]interface{}{
  109. "description": "Error response",
  110. "schema": map[string]interface{}{
  111. "$ref": "#/definitions/Error",
  112. },
  113. },
  114. },
  115. },
  116. }
  117. s["definitions"].(map[string]interface{})["GraphQLRequest"] = map[string]interface{}{
  118. "type": "object",
  119. "properties": map[string]interface{}{
  120. "operationName": map[string]interface{}{
  121. "description": "GraphQL query operation name.",
  122. "type": "string",
  123. },
  124. "query": map[string]interface{}{
  125. "description": "GraphQL query.",
  126. "type": "string",
  127. },
  128. "variables": map[string]interface{}{
  129. "description": "GraphQL query variable values.",
  130. "type": "object",
  131. },
  132. },
  133. }
  134. }