From 01ebf87f660a5fd9c0dab614baa5b289befa65c0 Mon Sep 17 00:00:00 2001 From: Kiryl Mialeshka <8974488+meskill@users.noreply.github.com> Date: Mon, 9 Dec 2024 09:00:01 +0100 Subject: [PATCH] feat: drop support for `json` `yaml` from `Config` (#3201) Co-authored-by: laststylebender <43403528+laststylebender14@users.noreply.github.com> Co-authored-by: blacksmith-sh[bot] <157653362+blacksmith-sh[bot]@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Tushar Mathur --- .graphqlrc.yml | 2 - examples/jsonplaceholder.json | 119 -- examples/jsonplaceholder.yml | 73 -- examples/jsonplaceholder_batch.json | 113 -- examples/jsonplaceholder_batch.yml | 71 -- generated/.tailcallrc.schema.json | 1056 +---------------- src/core/config/config.rs | 86 +- src/core/config/reader.rs | 53 +- .../fixtures/nested-unions-recursive.graphql | 32 + .../fixtures/nested-unions.graphql | 32 + .../fixtures/recursive-input.graphql | 17 + .../fixtures/union-in-type.graphql | 33 + .../config/transformer/fixtures/union.graphql | 22 + src/core/config/transformer/nested_unions.rs | 11 +- .../config/transformer/union_input_type.rs | 17 +- .../configs/yaml-nested-unions-recursive.yaml | 56 - .../fixtures/configs/yaml-nested-unions.yaml | 56 - .../configs/yaml-recursive-input.yaml | 34 - .../fixtures/configs/yaml-union-in-type.yaml | 64 - .../fixtures/configs/yaml-union.yaml | 40 - .../snapshots/test-enum-empty.md_error.snap | 3 +- tests/execution/batching-disabled.md | 74 +- tests/execution/batching.md | 54 +- tests/execution/cache-control.md | 70 +- tests/execution/custom-headers.md | 43 +- tests/execution/env-value.md | 86 +- tests/execution/https.md | 61 - tests/execution/recursive-types-json.md | 211 ---- tests/execution/ref-other-nested.md | 84 +- .../execution/request-to-upstream-batching.md | 80 +- tests/execution/simple-query.md | 51 +- tests/execution/test-enum-empty.md | 46 +- tests/execution/test-interface-from-json.md | 47 - tests/execution/test-static-value.md | 62 - tests/execution/upstream-batching.md | 77 +- tests/execution/with-args-url.md | 59 +- tests/execution/yaml-nested-unions.md | 86 +- tests/execution/yaml-union-in-type.md | 87 +- tests/execution/yaml-union.md | 78 +- tests/graphql_spec.graphql | 1 - 40 files changed, 425 insertions(+), 2922 deletions(-) delete mode 100644 examples/jsonplaceholder.json delete mode 100644 examples/jsonplaceholder.yml delete mode 100644 examples/jsonplaceholder_batch.json delete mode 100644 examples/jsonplaceholder_batch.yml create mode 100644 src/core/config/transformer/fixtures/nested-unions-recursive.graphql create mode 100644 src/core/config/transformer/fixtures/nested-unions.graphql create mode 100644 src/core/config/transformer/fixtures/recursive-input.graphql create mode 100644 src/core/config/transformer/fixtures/union-in-type.graphql create mode 100644 src/core/config/transformer/fixtures/union.graphql delete mode 100644 tailcall-fixtures/fixtures/configs/yaml-nested-unions-recursive.yaml delete mode 100644 tailcall-fixtures/fixtures/configs/yaml-nested-unions.yaml delete mode 100644 tailcall-fixtures/fixtures/configs/yaml-recursive-input.yaml delete mode 100644 tailcall-fixtures/fixtures/configs/yaml-union-in-type.yaml delete mode 100644 tailcall-fixtures/fixtures/configs/yaml-union.yaml delete mode 100644 tests/execution/https.md delete mode 100644 tests/execution/recursive-types-json.md delete mode 100644 tests/execution/test-interface-from-json.md delete mode 100644 tests/execution/test-static-value.md delete mode 100644 tests/graphql_spec.graphql diff --git a/.graphqlrc.yml b/.graphqlrc.yml index 1e8b8bf1c2..8e19f17adb 100644 --- a/.graphqlrc.yml +++ b/.graphqlrc.yml @@ -1,5 +1,3 @@ schema: - "./examples/jsonplaceholder.graphql" - "./generated/.tailcallrc.graphql" - # for tests inside the repo - - "./tests/graphql_spec.graphql" diff --git a/examples/jsonplaceholder.json b/examples/jsonplaceholder.json deleted file mode 100644 index 802964d591..0000000000 --- a/examples/jsonplaceholder.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "$schema": "../generated/.tailcallrc.schema.json", - "server": { - "hostname": "0.0.0.0", - "port": 8000 - }, - "upstream": { - "httpCache": 42 - }, - "schema": { - "query": "Query" - }, - "types": { - "Post": { - "fields": { - "body": { - "type": { - "name": "String", - "required": true - } - }, - "id": { - "type": { - "name": "Int", - "required": true - } - }, - "title": { - "type": { - "name": "String", - "required": true - } - }, - "user": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/{{value.userId}}" - } - }, - "userId": { - "type": { - "name": "Int", - "required": true - } - } - } - }, - "Query": { - "fields": { - "posts": { - "type": { - "list": { - "name": "Post" - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts" - } - }, - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int", - "required": true - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/{{args.id}}" - } - } - } - }, - "User": { - "fields": { - "email": { - "type": { - "name": "String", - "required": true - } - }, - "id": { - "type": { - "name": "Int", - "required": true - } - }, - "name": { - "type": { - "name": "String", - "required": true - } - }, - "phone": { - "type": { - "name": "String" - } - }, - "username": { - "type": { - "name": "String", - "required": true - } - }, - "website": { - "type": { - "name": "String" - } - } - } - } - } -} diff --git a/examples/jsonplaceholder.yml b/examples/jsonplaceholder.yml deleted file mode 100644 index 79c94fb96a..0000000000 --- a/examples/jsonplaceholder.yml +++ /dev/null @@ -1,73 +0,0 @@ -server: - hostname: 0.0.0.0 - port: 8000 -upstream: - httpCache: 42 -schema: - query: Query -types: - Post: - fields: - body: - type: - name: String - required: true - id: - type: - name: Int - required: true - title: - type: - name: String - required: true - user: - type: - name: User - http: - url: http://jsonplaceholder.typicode.com/users/{{value.userId}} - userId: - type: - name: Int - required: true - Query: - fields: - posts: - type: - list: - name: Post - http: - url: http://jsonplaceholder.typicode.com/posts - user: - type: - name: User - args: - id: - type: - name: Int - required: true - http: - url: http://jsonplaceholder.typicode.com/users/{{args.id}} - User: - fields: - email: - type: - name: String - required: true - id: - type: - name: Int - required: true - name: - type: - name: String - required: true - phone: - type: - name: String - username: - type: - name: String - required: true - website: - type: - name: String diff --git a/examples/jsonplaceholder_batch.json b/examples/jsonplaceholder_batch.json deleted file mode 100644 index 72059725b7..0000000000 --- a/examples/jsonplaceholder_batch.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "server": { - "port": 8000 - }, - "upstream": { - "httpCache": 42, - "batch": { - "maxSize": 1000, - "delay": 1, - "headers": [] - } - }, - "schema": { - "query": "Query" - }, - "types": { - "Post": { - "fields": { - "body": { - "type": { - "name": "String", - "required": true - } - }, - "id": { - "type": { - "name": "Int", - "required": true - } - }, - "title": { - "type": { - "name": "String", - "required": true - } - }, - "user": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users", - "query": [ - { - "key": "id", - "value": "{{value.userId}}" - } - ], - "batchKey": ["id"] - } - }, - "userId": { - "type": { - "name": "Int", - "required": true - } - } - } - }, - "Query": { - "fields": { - "posts": { - "type": { - "list": { - "name": "Post" - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts" - } - } - } - }, - "User": { - "fields": { - "email": { - "type": { - "name": "String", - "required": true - } - }, - "id": { - "type": { - "name": "Int", - "required": true - } - }, - "name": { - "type": { - "name": "String", - "required": true - } - }, - "phone": { - "type": { - "name": "String" - } - }, - "username": { - "type": { - "name": "String", - "required": true - } - }, - "website": { - "type": { - "name": "String" - } - } - } - } - } -} diff --git a/examples/jsonplaceholder_batch.yml b/examples/jsonplaceholder_batch.yml deleted file mode 100644 index 78ac2980f9..0000000000 --- a/examples/jsonplaceholder_batch.yml +++ /dev/null @@ -1,71 +0,0 @@ -server: - port: 8000 -upstream: - httpCache: 42 - batch: - maxSize: 1000 - delay: 1 - headers: [] -schema: - query: Query -types: - Post: - fields: - body: - type: - name: String - required: true - id: - type: - name: Int - required: true - title: - type: - name: String - required: true - user: - type: - name: User - http: - url: http://jsonplaceholder.typicode.com/users - query: - - key: id - value: "{{value.userId}}" - batchKey: - - id - userId: - type: - name: Int - required: true - Query: - fields: - posts: - type: - list: - name: Post - http: - url: http://jsonplaceholder.typicode.com/posts - User: - fields: - email: - type: - name: String - required: true - id: - type: - name: Int - required: true - name: - type: - name: String - required: true - phone: - type: - name: String - username: - type: - name: String - required: true - website: - type: - name: String diff --git a/generated/.tailcallrc.schema.json b/generated/.tailcallrc.schema.json index ffb4d75c7e..e76f874e55 100644 --- a/generated/.tailcallrc.schema.json +++ b/generated/.tailcallrc.schema.json @@ -2,32 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Config", "type": "object", - "required": [ - "schema" - ], "properties": { - "enums": { - "description": "A map of all the enum types in the schema", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Enum" - } - }, - "links": { - "description": "A list of all links in the schema.", - "type": "array", - "items": { - "$ref": "#/definitions/Link" - } - }, - "schema": { - "description": "Specifies the entry points for query and mutation in the generated GraphQL schema.", - "allOf": [ - { - "$ref": "#/definitions/RootSchema" - } - ] - }, "server": { "description": "Dictates how the server behaves and helps tune tailcall for all ingress requests. Features such as request batching, SSL, HTTP2 etc. can be configured here.", "default": {}, @@ -45,21 +20,6 @@ } ] }, - "types": { - "description": "A map of all the types in the schema.", - "default": {}, - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Type" - } - }, - "unions": { - "description": "A map of all the union types in the schema.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Union" - } - }, "upstream": { "description": "Dictates how tailcall should handle upstream requests/responses. Tuning upstream can improve performance and reliability for connections.", "default": {}, @@ -71,44 +31,6 @@ } }, "definitions": { - "AddField": { - "description": "The @addField operator simplifies data structures and queries by adding a field that inlines or flattens a nested field or node within your schema. more info [here](https://tailcall.run/docs/guides/operators/#addfield)", - "type": "object", - "required": [ - "name", - "path" - ], - "properties": { - "name": { - "description": "Name of the new field to be added", - "type": "string" - }, - "path": { - "description": "Path of the data where the field should point to", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - }, - "Alias": { - "description": "The @alias directive indicates that aliases of one enum value.", - "type": "object", - "required": [ - "options" - ], - "properties": { - "options": { - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - } - } - }, "Apollo": { "type": "object", "required": [ @@ -147,34 +69,6 @@ } } }, - "Arg": { - "type": "object", - "required": [ - "type" - ], - "properties": { - "default_value": true, - "doc": { - "type": [ - "string", - "null" - ] - }, - "modify": { - "anyOf": [ - { - "$ref": "#/definitions/Modify" - }, - { - "type": "null" - } - ] - }, - "type": { - "$ref": "#/definitions/Type2" - } - } - }, "Batch": { "type": "object", "properties": { @@ -206,45 +100,6 @@ "title": "Bytes", "description": "Field whose value is a sequence of bytes." }, - "Cache": { - "description": "The @cache operator enables caching for the query, field or type it is applied to.", - "type": "object", - "required": [ - "maxAge" - ], - "properties": { - "maxAge": { - "description": "Specifies the duration, in milliseconds, of how long the value has to be stored in the cache.", - "type": "integer", - "format": "uint64", - "minimum": 1.0 - } - }, - "additionalProperties": false - }, - "Call": { - "description": "Provides the ability to refer to multiple fields in the Query or Mutation root.", - "type": "object", - "required": [ - "steps" - ], - "properties": { - "dedupe": { - "description": "Enables deduplication of IO operations to enhance performance.\n\nThis flag prevents duplicate IO requests from being executed concurrently, reducing resource load. Caution: May lead to issues with APIs that expect unique results for identical inputs, such as nonce-based APIs.", - "type": [ - "boolean", - "null" - ] - }, - "steps": { - "description": "Steps are composed together to form a call. If you have multiple steps, the output of the previous step is passed as input to the next step.", - "type": "array", - "items": { - "$ref": "#/definitions/Step" - } - } - } - }, "Cors": { "description": "Type to configure Cross-Origin Resource Sharing (CORS) for a server.", "type": "object", @@ -322,34 +177,6 @@ "title": "DateTime", "description": "Field whose value conforms to the standard datetime format as specified in RFC 3339 (https://datatracker.ietf.org/doc/html/rfc3339\")." }, - "Directive": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "arguments": { - "type": "object", - "additionalProperties": true - }, - "name": { - "type": "string" - } - } - }, - "Discriminate": { - "description": "The `@discriminate` directive is used to drive Tailcall discriminator to use a field of an object to resolve the type. For example with the directive applied on a field `@discriminate(field: \"object_type\")` and the given value `{\"foo\": \"bar\", \"object_type\": \"Buzz\"}` the resolved type of the object will be `Buzz`. If `field` is not applied it defaults to \"type\". The `field` does not have to be part of the GraphQL Schema, but it is required to be part of the JSON response. In case this field is missing from the response an appropriate error message will be displayed.", - "type": "object", - "properties": { - "field": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, "Email": { "title": "Email", "description": "Field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address." @@ -358,243 +185,6 @@ "title": "Empty", "description": "Empty scalar type represents an empty value." }, - "Encoding": { - "type": "string", - "enum": [ - "ApplicationJson", - "ApplicationXWwwFormUrlencoded" - ] - }, - "Enum": { - "description": "Definition of GraphQL enum type", - "type": "object", - "required": [ - "variants" - ], - "properties": { - "doc": { - "type": [ - "string", - "null" - ] - }, - "variants": { - "type": "array", - "items": { - "$ref": "#/definitions/Variant" - }, - "uniqueItems": true - } - } - }, - "Expr": { - "description": "The `@expr` operators allows you to specify an expression that can evaluate to a value. The expression can be a static value or built form a Mustache template. schema.", - "type": "object", - "required": [ - "body" - ], - "properties": { - "body": true - }, - "additionalProperties": false - }, - "Field": { - "description": "A field definition containing all the metadata information about resolving a field.", - "type": [ - "object", - "array" - ], - "items": { - "$ref": "#/definitions/Resolver" - }, - "properties": { - "args": { - "description": "Map of argument name and its definition.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Arg" - } - }, - "cache": { - "description": "Sets the cache configuration for a field", - "anyOf": [ - { - "$ref": "#/definitions/Cache" - }, - { - "type": "null" - } - ] - }, - "default_value": { - "description": "Stores the default value for the field" - }, - "directives": { - "description": "Any additional directives", - "type": "array", - "items": { - "$ref": "#/definitions/Directive" - } - }, - "discriminate": { - "description": "Used to overwrite the default discrimination strategy", - "anyOf": [ - { - "$ref": "#/definitions/Discriminate" - }, - { - "type": "null" - } - ] - }, - "doc": { - "description": "Publicly visible documentation for the field.", - "type": [ - "string", - "null" - ] - }, - "modify": { - "description": "Allows modifying existing fields.", - "anyOf": [ - { - "$ref": "#/definitions/Modify" - }, - { - "type": "null" - } - ] - }, - "omit": { - "description": "Omits a field from public consumption.", - "anyOf": [ - { - "$ref": "#/definitions/Omit" - }, - { - "type": "null" - } - ] - }, - "protected": { - "description": "Marks field as protected by auth provider", - "default": null, - "anyOf": [ - { - "$ref": "#/definitions/Protected" - }, - { - "type": "null" - } - ] - }, - "type": { - "description": "Refers to the type of the value the field can be resolved to.", - "allOf": [ - { - "$ref": "#/definitions/Type2" - } - ] - } - } - }, - "GraphQL": { - "description": "The @graphQL operator allows to specify GraphQL API server request to fetch data from.", - "type": "object", - "required": [ - "name", - "url" - ], - "properties": { - "args": { - "description": "Named arguments for the requested field. More info [here](https://tailcall.run/docs/guides/operators/#args)", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/KeyValue" - } - }, - "batch": { - "description": "If the upstream GraphQL server supports request batching, you can specify the 'batch' argument to batch several requests into a single batch request.\n\nMake sure you have also specified batch settings to the `@upstream` and to the `@graphQL` operator.", - "type": "boolean" - }, - "dedupe": { - "description": "Enables deduplication of IO operations to enhance performance.\n\nThis flag prevents duplicate IO requests from being executed concurrently, reducing resource load. Caution: May lead to issues with APIs that expect unique results for identical inputs, such as nonce-based APIs.", - "type": "boolean" - }, - "headers": { - "description": "The headers parameter allows you to customize the headers of the GraphQL request made by the `@graphQL` operator. It is used by specifying a key-value map of header names and their values.", - "type": "array", - "items": { - "$ref": "#/definitions/KeyValue" - } - }, - "name": { - "description": "Specifies the root field on the upstream to request data from. This maps a field in your schema to a field in the upstream schema. When a query is received for this field, Tailcall requests data from the corresponding upstream field.", - "type": "string" - }, - "url": { - "description": "This refers URL of the API.", - "type": "string" - } - }, - "additionalProperties": false - }, - "Grpc": { - "description": "The @grpc operator indicates that a field or node is backed by a gRPC API.\n\nFor instance, if you add the @grpc operator to the `users` field of the Query type with a service argument of `NewsService` and method argument of `GetAllNews`, it signifies that the `users` field is backed by a gRPC API. The `service` argument specifies the name of the gRPC service. The `method` argument specifies the name of the gRPC method. In this scenario, the GraphQL server will make a gRPC request to the gRPC endpoint specified when the `users` field is queried.", - "type": "object", - "required": [ - "method", - "url" - ], - "properties": { - "batchKey": { - "description": "The `batchKey` dictates the path Tailcall will follow to group the returned items from the batch request. For more details please refer out [n + 1 guide](https://tailcall.run/docs/guides/n+1#solving-using-batching).", - "type": "array", - "items": { - "type": "string" - } - }, - "body": { - "description": "This refers to the arguments of your gRPC call. You can pass it as a static object or use Mustache template for dynamic parameters. These parameters will be added in the body in `protobuf` format." - }, - "dedupe": { - "description": "Enables deduplication of IO operations to enhance performance.\n\nThis flag prevents duplicate IO requests from being executed concurrently, reducing resource load. Caution: May lead to issues with APIs that expect unique results for identical inputs, such as nonce-based APIs.", - "type": [ - "boolean", - "null" - ] - }, - "headers": { - "description": "The `headers` parameter allows you to customize the headers of the HTTP request made by the `@grpc` operator. It is used by specifying a key-value map of header names and their values. Note: content-type is automatically set to application/grpc", - "type": "array", - "items": { - "$ref": "#/definitions/KeyValue" - } - }, - "method": { - "description": "This refers to the gRPC method you're going to call. For instance `GetAllNews`.", - "type": "string" - }, - "onResponseBody": { - "description": "Specifies a JavaScript function to be executed after receiving the response body. This function can modify or transform the response body before it's sent back to the client.", - "type": [ - "string", - "null" - ] - }, - "select": { - "description": "You can use `select` with mustache syntax to re-construct the directives response to the desired format. This is useful when data are deeply nested or want to keep specific fields only from the response.\n\n* EXAMPLE 1: if we have a call that returns `{ \"user\": { \"items\": [...], ... } ... }` we can use `\"{{.user.items}}\"`, to extract the `items`. * EXAMPLE 2: if we have a call that returns `{ \"foo\": \"bar\", \"fizz\": { \"buzz\": \"eggs\", ... }, ... }` we can use { foo: \"{{.foo}}\", buzz: \"{{.fizz.buzz}}\" }`" - }, - "url": { - "description": "This refers to URL of the API.", - "type": "string" - } - }, - "additionalProperties": false - }, "Headers": { "type": "object", "properties": { @@ -643,110 +233,6 @@ } } }, - "Http": { - "description": "The @http operator indicates that a field or node is backed by a REST API.\n\nFor instance, if you add the @http operator to the `users` field of the Query type with a path argument of `\"/users\"`, it signifies that the `users` field is backed by a REST API. The path argument specifies the path of the REST API. In this scenario, the GraphQL server will make a GET request to the API endpoint specified when the `users` field is queried.", - "type": "object", - "required": [ - "url" - ], - "properties": { - "batchKey": { - "description": "The `batchKey` dictates the path Tailcall will follow to group the returned items from the batch request. For more details please refer out [n + 1 guide](https://tailcall.run/docs/guides/n+1#solving-using-batching).", - "type": "array", - "items": { - "type": "string" - } - }, - "body": { - "description": "The body of the API call. It's used for methods like POST or PUT that send data to the server. You can pass it as a static object or use a Mustache template to substitute variables from the GraphQL variables.", - "type": [ - "string", - "null" - ] - }, - "dedupe": { - "description": "Enables deduplication of IO operations to enhance performance.\n\nThis flag prevents duplicate IO requests from being executed concurrently, reducing resource load. Caution: May lead to issues with APIs that expect unique results for identical inputs, such as nonce-based APIs.", - "type": [ - "boolean", - "null" - ] - }, - "encoding": { - "description": "The `encoding` parameter specifies the encoding of the request body. It can be `ApplicationJson` or `ApplicationXWwwFormUrlEncoded`. @default `ApplicationJson`.", - "allOf": [ - { - "$ref": "#/definitions/Encoding" - } - ] - }, - "headers": { - "description": "The `headers` parameter allows you to customize the headers of the HTTP request made by the `@http` operator. It is used by specifying a key-value map of header names and their values.", - "type": "array", - "items": { - "$ref": "#/definitions/KeyValue" - } - }, - "input": { - "description": "Schema of the input of the API call. It is automatically inferred in most cases.", - "anyOf": [ - { - "$ref": "#/definitions/schema" - }, - { - "type": "null" - } - ] - }, - "method": { - "description": "This refers to the HTTP method of the API call. Commonly used methods include `GET`, `POST`, `PUT`, `DELETE` etc. @default `GET`.", - "allOf": [ - { - "$ref": "#/definitions/Method" - } - ] - }, - "onRequest": { - "description": "onRequest field in @http directive gives the ability to specify the request interception handler.", - "type": [ - "string", - "null" - ] - }, - "onResponseBody": { - "description": "Specifies a JavaScript function to be executed after receiving the response body. This function can modify or transform the response body before it's sent back to the client.", - "type": [ - "string", - "null" - ] - }, - "output": { - "description": "Schema of the output of the API call. It is automatically inferred in most cases.", - "anyOf": [ - { - "$ref": "#/definitions/schema" - }, - { - "type": "null" - } - ] - }, - "query": { - "description": "This represents the query parameters of your API call. You can pass it as a static object or use Mustache template for dynamic parameters. These parameters will be added to the URL. NOTE: Query parameter order is critical for batching in Tailcall. The first parameter referencing a field in the current value using mustache syntax is automatically selected as the batching parameter.", - "type": "array", - "items": { - "$ref": "#/definitions/URLQuery" - } - }, - "select": { - "description": "You can use `select` with mustache syntax to re-construct the directives response to the desired format. This is useful when data are deeply nested or want to keep specific fields only from the response.\n\n* EXAMPLE 1: if we have a call that returns `{ \"user\": { \"items\": [...], ... } ... }` we can use `\"{{.user.items}}\"`, to extract the `items`. * EXAMPLE 2: if we have a call that returns `{ \"foo\": \"bar\", \"fizz\": { \"buzz\": \"eggs\", ... }, ... }` we can use { foo: \"{{.foo}}\", buzz: \"{{.fizz.buzz}}\" }`" - }, - "url": { - "description": "This refers to URL of the API.", - "type": "string" - } - }, - "additionalProperties": false - }, "HttpVersion": { "type": "string", "enum": [ @@ -774,17 +260,6 @@ "title": "Int8", "description": "Field whose value is an 8-bit signed integer." }, - "JS": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string" - } - } - }, "JSON": { "title": "JSON", "description": "Field whose value conforms to the standard JSON format as specified in RFC 8259 (https://datatracker.ietf.org/doc/html/rfc8259)." @@ -804,112 +279,6 @@ } } }, - "Link": { - "description": "The @link directive allows you to import external resources, such as configuration – which will be merged into the config importing it –, or a .proto file – which will be later used by `@grpc` directive –.", - "type": "object", - "properties": { - "headers": { - "description": "Custom headers for gRPC reflection server.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/KeyValue" - } - }, - "id": { - "description": "The id of the link. It is used to reference the link in the schema.", - "type": [ - "string", - "null" - ] - }, - "meta": { - "description": "Additional metadata pertaining to the linked resource." - }, - "src": { - "description": "The source of the link. It can be a URL or a path to a file. If a path is provided, it is relative to the file that imports the link.", - "type": "string" - }, - "type": { - "description": "The type of the link. It can be `Config`, or `Protobuf`.", - "allOf": [ - { - "$ref": "#/definitions/LinkType" - } - ] - } - }, - "additionalProperties": false - }, - "LinkType": { - "oneOf": [ - { - "description": "Points to another Tailcall Configuration file. The imported configuration will be merged into the importing configuration.", - "type": "string", - "enum": [ - "Config" - ] - }, - { - "description": "Points to a Protobuf file. The imported Protobuf file will be used by the `@grpc` directive. If your API exposes a reflection endpoint, you should set the type to `Grpc` instead.", - "type": "string", - "enum": [ - "Protobuf" - ] - }, - { - "description": "Points to a JS file. The imported JS file will be used by the `@js` directive.", - "type": "string", - "enum": [ - "Script" - ] - }, - { - "description": "Points to a Cert file. The imported Cert file will be used by the server to serve over HTTPS.", - "type": "string", - "enum": [ - "Cert" - ] - }, - { - "description": "Points to a Key file. The imported Key file will be used by the server to serve over HTTPS.", - "type": "string", - "enum": [ - "Key" - ] - }, - { - "description": "A trusted document that contains GraphQL operations (queries, mutations) that can be exposed a REST API using the `@rest` directive.", - "type": "string", - "enum": [ - "Operation" - ] - }, - { - "description": "Points to a Htpasswd file. The imported Htpasswd file will be used by the server to authenticate users.", - "type": "string", - "enum": [ - "Htpasswd" - ] - }, - { - "description": "Points to a Jwks file. The imported Jwks file will be used by the server to authenticate users.", - "type": "string", - "enum": [ - "Jwks" - ] - }, - { - "description": "Points to a reflection endpoint. The imported reflection endpoint will be used by the `@grpc` directive to resolve data from gRPC services.", - "type": "string", - "enum": [ - "Grpc" - ] - } - ] - }, "Method": { "type": "string", "enum": [ @@ -924,29 +293,6 @@ "TRACE" ] }, - "Modify": { - "type": "object", - "properties": { - "name": { - "type": [ - "string", - "null" - ] - }, - "omit": { - "type": [ - "boolean", - "null" - ] - } - }, - "additionalProperties": false - }, - "Omit": { - "description": "Used to omit a field from public consumption.", - "type": "object", - "additionalProperties": false - }, "OtlpExporter": { "description": "Output the opentelemetry data to otlp collector", "type": "object", @@ -984,27 +330,11 @@ }, "PrometheusFormat": { "description": "Output format for prometheus data", - "type": "string", - "enum": [ - "text", - "protobuf" - ] - }, - "Protected": { - "description": "Specifies the authentication requirements for accessing a field or type.\n\nThis allows you to control access by listing the IDs of authentication providers. - If `id` is not provided, all available providers must authorize the request. - If multiple provider IDs are listed, the request must be authorized by all of them.\n\nExample: If you want only specific providers to allow access, include their IDs in the list. Otherwise, leave it empty to require authorization from all available providers.", - "type": "object", - "properties": { - "id": { - "description": "List of authentication provider IDs that can access this field or type. - Leave empty to require authorization from all providers. - Include multiple IDs to require authorization from each one.", - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } - } - } + "type": "string", + "enum": [ + "text", + "protobuf" + ] }, "Proxy": { "type": "object", @@ -1017,105 +347,6 @@ } } }, - "Resolver": { - "oneOf": [ - { - "type": "object", - "required": [ - "http" - ], - "properties": { - "http": { - "$ref": "#/definitions/Http" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "grpc" - ], - "properties": { - "grpc": { - "$ref": "#/definitions/Grpc" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "graphql" - ], - "properties": { - "graphql": { - "$ref": "#/definitions/GraphQL" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "call" - ], - "properties": { - "call": { - "$ref": "#/definitions/Call" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "js" - ], - "properties": { - "js": { - "$ref": "#/definitions/JS" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "expr" - ], - "properties": { - "expr": { - "$ref": "#/definitions/Expr" - } - }, - "additionalProperties": false - } - ] - }, - "RootSchema": { - "type": "object", - "properties": { - "mutation": { - "type": [ - "string", - "null" - ] - }, - "query": { - "type": [ - "string", - "null" - ] - }, - "subscription": { - "type": [ - "string", - "null" - ] - } - } - }, "Routes": { "type": "object", "properties": { @@ -1305,31 +536,6 @@ } } }, - "Step": { - "description": "Provides the ability to refer to a field defined in the root Query or Mutation.", - "type": "object", - "properties": { - "args": { - "description": "The arguments that will override the actual arguments of the field.", - "type": "object", - "additionalProperties": true - }, - "mutation": { - "description": "The name of the field on the `Mutation` type that you want to call.", - "type": [ - "string", - "null" - ] - }, - "query": { - "description": "The name of the field on the `Query` type that you want to call.", - "type": [ - "string", - "null" - ] - } - } - }, "Telemetry": { "description": "The @telemetry directive facilitates seamless integration with OpenTelemetry, enhancing the observability of your GraphQL services powered by Tailcall. By leveraging this directive, developers gain access to valuable insights into the performance and behavior of their applications.", "type": "object", @@ -1406,121 +612,6 @@ } ] }, - "Type": { - "description": "Represents a GraphQL type. A type can be an object, interface, enum or scalar.", - "type": [ - "object", - "array" - ], - "items": { - "$ref": "#/definitions/Resolver" - }, - "required": [ - "fields" - ], - "properties": { - "added_fields": { - "description": "Additional fields to be added to the type", - "type": "array", - "items": { - "$ref": "#/definitions/AddField" - } - }, - "cache": { - "description": "Setting to indicate if the type can be cached.", - "anyOf": [ - { - "$ref": "#/definitions/Cache" - }, - { - "type": "null" - } - ] - }, - "directives": { - "description": "Any additional directives", - "type": "array", - "items": { - "$ref": "#/definitions/Directive" - } - }, - "doc": { - "description": "Documentation for the type that is publicly visible.", - "type": [ - "string", - "null" - ] - }, - "fields": { - "description": "A map of field name and its definition.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Field" - } - }, - "implements": { - "description": "Interfaces that the type implements.", - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - }, - "protected": { - "description": "Marks field as protected by auth providers", - "default": null, - "anyOf": [ - { - "$ref": "#/definitions/Protected" - }, - { - "type": "null" - } - ] - } - } - }, - "Type2": { - "description": "Type to represent GraphQL type usage with modifiers [spec](https://spec.graphql.org/October2021/#sec-Wrapping-Types)", - "anyOf": [ - { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "description": "Name of the type", - "type": "string" - }, - "required": { - "description": "Flag to indicate the type is required.", - "type": "boolean" - } - } - }, - { - "type": "object", - "required": [ - "list" - ], - "properties": { - "list": { - "description": "Type is a list", - "allOf": [ - { - "$ref": "#/definitions/Type2" - } - ] - }, - "required": { - "description": "Flag to indicate the type is required.", - "type": "boolean" - } - } - } - ] - }, "UInt128": { "title": "UInt128", "description": "Field whose value is a 128-bit unsigned integer." @@ -1541,52 +632,6 @@ "title": "UInt8", "description": "Field whose value is an 8-bit unsigned integer." }, - "URLQuery": { - "description": "The URLQuery input type represents a query parameter to be included in a URL.", - "type": "object", - "required": [ - "key", - "value" - ], - "properties": { - "key": { - "description": "The key or name of the query parameter.", - "type": "string" - }, - "skipEmpty": { - "description": "Determines whether to ignore query parameters with empty values.", - "type": [ - "boolean", - "null" - ] - }, - "value": { - "description": "The actual value or a mustache template to resolve the value dynamically for the query parameter.", - "type": "string" - } - } - }, - "Union": { - "type": "object", - "required": [ - "types" - ], - "properties": { - "doc": { - "type": [ - "string", - "null" - ] - }, - "types": { - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - } - } - }, "Upstream": { "description": "The `upstream` directive allows you to control various aspects of the upstream server connection. This includes settings like connection timeouts, keep-alive intervals, and more. If not specified, default values are used.", "type": "object", @@ -1737,97 +782,6 @@ "Url": { "title": "Url", "description": "Field whose value conforms to the standard URL format as specified in RFC 3986 (https://datatracker.ietf.org/doc/html/rfc3986)." - }, - "Variant": { - "description": "Definition of GraphQL value", - "type": "object", - "required": [ - "name" - ], - "properties": { - "alias": { - "anyOf": [ - { - "$ref": "#/definitions/Alias" - }, - { - "type": "null" - } - ] - }, - "name": { - "type": "string" - } - } - }, - "schema": { - "oneOf": [ - { - "type": "string", - "enum": [ - "Str", - "Num", - "Bool", - "Empty", - "Any" - ] - }, - { - "type": "object", - "required": [ - "Obj" - ], - "properties": { - "Obj": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/schema" - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Arr" - ], - "properties": { - "Arr": { - "$ref": "#/definitions/schema" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Opt" - ], - "properties": { - "Opt": { - "$ref": "#/definitions/schema" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Enum" - ], - "properties": { - "Enum": { - "type": "array", - "items": { - "type": "string" - }, - "uniqueItems": true - } - }, - "additionalProperties": false - } - ] } } } \ No newline at end of file diff --git a/src/core/config/config.rs b/src/core/config/config.rs index cccfa0eeaf..a58715bec1 100644 --- a/src/core/config/config.rs +++ b/src/core/config/config.rs @@ -1,7 +1,7 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::fmt::{self, Display}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use async_graphql::parser::types::ServiceDocument; use derive_setters::Setters; use indexmap::IndexMap; @@ -56,27 +56,28 @@ pub struct Config { /// /// Specifies the entry points for query and mutation in the generated /// GraphQL schema. + #[serde(skip)] pub schema: RootSchema, /// /// A map of all the types in the schema. - #[serde(default)] + #[serde(skip)] #[setters(skip)] pub types: BTreeMap, /// /// A map of all the union types in the schema. - #[serde(default, skip_serializing_if = "is_default")] + #[serde(skip)] pub unions: BTreeMap, /// /// A map of all the enum types in the schema - #[serde(default, skip_serializing_if = "is_default")] + #[serde(skip)] pub enums: BTreeMap, /// /// A list of all links in the schema. - #[serde(default, skip_serializing_if = "is_default")] + #[serde(skip)] pub links: Vec, /// Enable [opentelemetry](https://opentelemetry.io) support @@ -87,40 +88,31 @@ pub struct Config { /// /// Represents a GraphQL type. /// A type can be an object, interface, enum or scalar. -#[derive( - Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, schemars::JsonSchema, MergeRight, -)] +#[derive(Clone, Debug, Default, PartialEq, Eq, MergeRight)] pub struct Type { /// /// A map of field name and its definition. pub fields: BTreeMap, - #[serde(default, skip_serializing_if = "is_default")] /// /// Additional fields to be added to the type pub added_fields: Vec, - #[serde(default, skip_serializing_if = "is_default")] /// /// Documentation for the type that is publicly visible. pub doc: Option, - #[serde(default, skip_serializing_if = "is_default")] /// /// Interfaces that the type implements. pub implements: BTreeSet, - #[serde(default, skip_serializing_if = "is_default")] /// /// Setting to indicate if the type can be cached. pub cache: Option, /// /// Marks field as protected by auth providers - #[serde(default)] pub protected: Option, /// /// Apollo federation entity resolver. - #[serde(flatten, default, skip_serializing_if = "is_default")] pub resolvers: ResolverSet, /// /// Any additional directives - #[serde(default, skip_serializing_if = "is_default")] pub directives: Vec, } @@ -158,59 +150,38 @@ impl Type { } } -#[derive( - Serialize, - Deserialize, - Clone, - Debug, - Default, - Setters, - PartialEq, - Eq, - schemars::JsonSchema, - MergeRight, -)] +#[derive(Clone, Debug, Default, Setters, PartialEq, Eq, MergeRight)] #[setters(strip_option)] pub struct RootSchema { pub query: Option, - #[serde(default, skip_serializing_if = "is_default")] pub mutation: Option, - #[serde(default, skip_serializing_if = "is_default")] pub subscription: Option, } /// /// A field definition containing all the metadata information about resolving a /// field. -#[derive( - Serialize, Deserialize, Clone, Debug, Default, Setters, PartialEq, Eq, schemars::JsonSchema, -)] +#[derive(Clone, Debug, Default, Setters, PartialEq, Eq)] #[setters(strip_option)] pub struct Field { /// /// Refers to the type of the value the field can be resolved to. - #[serde(rename = "type", default, skip_serializing_if = "is_default")] pub type_of: crate::core::Type, /// /// Map of argument name and its definition. - #[serde(default, skip_serializing_if = "is_default")] - #[schemars(with = "HashMap::")] pub args: IndexMap, /// /// Publicly visible documentation for the field. - #[serde(default, skip_serializing_if = "is_default")] pub doc: Option, /// /// Allows modifying existing fields. - #[serde(default, skip_serializing_if = "is_default")] pub modify: Option, /// /// Omits a field from public consumption. - #[serde(default, skip_serializing_if = "is_default")] pub omit: Option, /// @@ -219,12 +190,10 @@ pub struct Field { /// /// Stores the default value for the field - #[serde(default, skip_serializing_if = "is_default")] pub default_value: Option, /// /// Marks field as protected by auth provider - #[serde(default)] pub protected: Option, /// @@ -233,12 +202,10 @@ pub struct Field { /// /// Resolver for the field - #[serde(flatten, default, skip_serializing_if = "is_default")] pub resolvers: ResolverSet, /// /// Any additional directives - #[serde(default, skip_serializing_if = "is_default")] pub directives: Vec, } @@ -288,32 +255,26 @@ impl Field { } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Inline { pub path: Vec, } -#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, schemars::JsonSchema)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct Arg { - #[serde(rename = "type")] pub type_of: crate::core::Type, - #[serde(default, skip_serializing_if = "is_default")] pub doc: Option, - #[serde(default, skip_serializing_if = "is_default")] pub modify: Option, - #[serde(default, skip_serializing_if = "is_default")] pub default_value: Option, } -#[derive( - Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, schemars::JsonSchema, MergeRight, -)] +#[derive(Clone, Debug, Default, PartialEq, Eq, MergeRight)] pub struct Union { pub types: BTreeSet, pub doc: Option, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, schemars::JsonSchema, MergeRight)] +#[derive(Clone, Debug, PartialEq, Eq, MergeRight)] /// Definition of GraphQL enum type pub struct Enum { pub variants: BTreeSet, @@ -321,26 +282,14 @@ pub struct Enum { } /// Definition of GraphQL value -#[derive( - Serialize, - Deserialize, - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - schemars::JsonSchema, - MergeRight, -)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, MergeRight)] pub struct Variant { pub name: String, // directive: alias pub alias: Option, } -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "lowercase")] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub enum GraphQLOperationType { #[default] Query, @@ -442,8 +391,7 @@ impl Config { pub fn from_source(source: Source, schema: &str) -> Result { match source { Source::GraphQL => Ok(Config::from_sdl(schema).to_result()?), - Source::Json => Ok(Config::from_json(schema)?), - Source::Yml => Ok(Config::from_yaml(schema)?), + _ => Err(anyhow!("Only the graphql config is currently supported")), } } diff --git a/src/core/config/reader.rs b/src/core/config/reader.rs index f6d539360f..175291e865 100644 --- a/src/core/config/reader.rs +++ b/src/core/config/reader.rs @@ -273,40 +273,33 @@ mod reader_tests { async fn test_all() { let runtime = crate::core::runtime::test::init(None); + let server = start_mock_server(); let mut cfg = Config::default(); - cfg.schema.query = Some("Test".to_string()); - cfg = cfg.types([("Test", Type::default())].to_vec()); + cfg = cfg.types([("User", Type::default())].to_vec()); - let server = start_mock_server(); - let header_server = server.mock(|when, then| { - when.method(httpmock::Method::GET).path("/bar.graphql"); + let foo_mock = server.mock(|when, then| { + when.method(httpmock::Method::GET).path("/foo.graphql"); then.status(200).body(cfg.to_sdl()); }); - let json = runtime - .file - .read("examples/jsonplaceholder.json") - .await - .unwrap(); + let mut cfg = Config::default(); + cfg.schema.query = Some("Test".to_string()); + cfg = cfg.types([("Test", Type::default())].to_vec()); - let foo_json_server = server.mock(|when, then| { - when.method(httpmock::Method::GET).path("/foo.json"); - then.status(200).body(json); + let bar_mock = server.mock(|when, then| { + when.method(httpmock::Method::GET).path("/bar.graphql"); + then.status(200).body(cfg.to_sdl()); }); let port = server.port(); - let files: Vec = [ - "examples/jsonplaceholder.yml", // config from local file - format!("http://localhost:{port}/bar.graphql").as_str(), // with content-type header - format!("http://localhost:{port}/foo.json").as_str(), // with url extension - ] - .iter() - .map(|x| x.to_string()) - .collect(); + let files = vec![ + format!("http://localhost:{port}/foo.graphql"), + format!("http://localhost:{port}/bar.graphql"), + ]; let cr = ConfigReader::init(runtime); let c = cr.read_all(&files).await.unwrap(); assert_eq!( - ["Post", "Query", "Test", "User"] + ["Test", "User"] .iter() .map(|i| i.to_string()) .collect::>(), @@ -315,22 +308,18 @@ mod reader_tests { .map(|i| i.to_string()) .collect::>() ); - foo_json_server.assert(); // checks if the request was actually made - header_server.assert(); + foo_mock.assert(); + bar_mock.assert(); } #[tokio::test] async fn test_local_files() { let runtime = crate::core::runtime::test::init(None); - let files: Vec = [ - "examples/jsonplaceholder.yml", - "examples/jsonplaceholder.graphql", - "examples/jsonplaceholder.json", - ] - .iter() - .map(|x| x.to_string()) - .collect(); + let files: Vec = ["examples/jsonplaceholder.graphql"] + .iter() + .map(|x| x.to_string()) + .collect(); let cr = ConfigReader::init(runtime); let c = cr.read_all(&files).await.unwrap(); assert_eq!( diff --git a/src/core/config/transformer/fixtures/nested-unions-recursive.graphql b/src/core/config/transformer/fixtures/nested-unions-recursive.graphql new file mode 100644 index 0000000000..2fb810f272 --- /dev/null +++ b/src/core/config/transformer/fixtures/nested-unions-recursive.graphql @@ -0,0 +1,32 @@ +schema { + query: Query +} + +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +type T4 { + t4: String +} + +type T5 { + t5: Boolean +} + +union U1 = T1 | T2 | T3 | U2 +union U2 = T3 | T4 | U1 +union U = U1 | U2 | T5 + +type Query { + test(u: U!): U @http(url: "http://localhost/users/{{args.u}}") +} diff --git a/src/core/config/transformer/fixtures/nested-unions.graphql b/src/core/config/transformer/fixtures/nested-unions.graphql new file mode 100644 index 0000000000..dfb418246c --- /dev/null +++ b/src/core/config/transformer/fixtures/nested-unions.graphql @@ -0,0 +1,32 @@ +schema { + query: Query +} + +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +type T4 { + t4: String +} + +type T5 { + t5: Boolean +} + +union U1 = T1 | T2 | T3 +union U2 = T3 | T4 +union U = U1 | U2 | T5 + +type Query { + test(u: U!): U @http(url: "http://localhost/users/{{args.u}}") +} diff --git a/src/core/config/transformer/fixtures/recursive-input.graphql b/src/core/config/transformer/fixtures/recursive-input.graphql new file mode 100644 index 0000000000..23899c7844 --- /dev/null +++ b/src/core/config/transformer/fixtures/recursive-input.graphql @@ -0,0 +1,17 @@ +schema @server(port: 8000) { + query: Query +} + +type Bar { + name: Foo + rec: Bar +} + +type Foo { + name: String +} + +type Query { + bars(filter: Bar): String + @graphQL(url: "http://localhost", args: [{key: "baz", value: "{{.args.baz}}"}], name: "bars") +} diff --git a/src/core/config/transformer/fixtures/union-in-type.graphql b/src/core/config/transformer/fixtures/union-in-type.graphql new file mode 100644 index 0000000000..8c58a1b0e1 --- /dev/null +++ b/src/core/config/transformer/fixtures/union-in-type.graphql @@ -0,0 +1,33 @@ +schema { + query: Query +} + +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +type NU { + test: String + u: U +} + +type NNU { + other: Int + new: Boolean + nu: NU +} + +union U = T1 | T2 | T3 + +type Query { + test(nu: NU!, nnu: NNU): U @http(url: "http://localhost/users/{{args.nu.u}}") +} diff --git a/src/core/config/transformer/fixtures/union.graphql b/src/core/config/transformer/fixtures/union.graphql new file mode 100644 index 0000000000..71ab1f38cb --- /dev/null +++ b/src/core/config/transformer/fixtures/union.graphql @@ -0,0 +1,22 @@ +schema { + query: Query +} + +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +union U = T1 | T2 | T3 + +type Query { + test(u: U!): U @http(url: "http://localhost/users/{{args.u}}") +} diff --git a/src/core/config/transformer/nested_unions.rs b/src/core/config/transformer/nested_unions.rs index faab9d98ed..f7dea98cd1 100644 --- a/src/core/config/transformer/nested_unions.rs +++ b/src/core/config/transformer/nested_unions.rs @@ -75,14 +75,12 @@ mod tests { use tailcall_valid::Validator; use super::NestedUnions; - use crate::core::config::Config; use crate::core::transform::Transform; + use crate::include_config; #[test] fn test_nested_unions() { - let config = - std::fs::read_to_string(tailcall_fixtures::configs::YAML_NESTED_UNIONS).unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/nested-unions.graphql").unwrap(); let config = NestedUnions.transform(config).to_result().unwrap(); assert_snapshot!(config.to_sdl()); @@ -90,10 +88,7 @@ mod tests { #[test] fn test_nested_unions_recursive() { - let config = - std::fs::read_to_string(tailcall_fixtures::configs::YAML_NESTED_UNIONS_RECURSIVE) - .unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/nested-unions-recursive.graphql").unwrap(); let error = NestedUnions.transform(config).to_result().unwrap_err(); assert_snapshot!(error); diff --git a/src/core/config/transformer/union_input_type.rs b/src/core/config/transformer/union_input_type.rs index 906650dd6d..ca44f83141 100644 --- a/src/core/config/transformer/union_input_type.rs +++ b/src/core/config/transformer/union_input_type.rs @@ -285,13 +285,12 @@ mod tests { use tailcall_valid::Validator; use super::UnionInputType; - use crate::core::config::Config; use crate::core::transform::Transform; + use crate::include_config; #[test] fn test_union() { - let config = std::fs::read_to_string(tailcall_fixtures::configs::YAML_UNION).unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/union.graphql").unwrap(); let config = UnionInputType.transform(config).to_result().unwrap(); assert_snapshot!(config.to_sdl()); @@ -299,9 +298,7 @@ mod tests { #[test] fn test_union_in_type() { - let config = - std::fs::read_to_string(tailcall_fixtures::configs::YAML_UNION_IN_TYPE).unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/union-in-type.graphql").unwrap(); let config = UnionInputType.transform(config).to_result().unwrap(); assert_snapshot!(config.to_sdl()); @@ -309,18 +306,14 @@ mod tests { #[test] fn test_nested_unions() { - let config = - std::fs::read_to_string(tailcall_fixtures::configs::YAML_NESTED_UNIONS).unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/nested-unions.graphql").unwrap(); let config = UnionInputType.transform(config).to_result().unwrap(); assert_snapshot!(config.to_sdl()); } #[test] fn test_recursive_input() { - let config = - std::fs::read_to_string(tailcall_fixtures::configs::YAML_RECURSIVE_INPUT).unwrap(); - let config = Config::from_yaml(&config).unwrap(); + let config = include_config!("./fixtures/recursive-input.graphql").unwrap(); let config = UnionInputType.transform(config).to_result().unwrap(); assert_snapshot!(config.to_sdl()); diff --git a/tailcall-fixtures/fixtures/configs/yaml-nested-unions-recursive.yaml b/tailcall-fixtures/fixtures/configs/yaml-nested-unions-recursive.yaml deleted file mode 100644 index 829afc48ff..0000000000 --- a/tailcall-fixtures/fixtures/configs/yaml-nested-unions-recursive.yaml +++ /dev/null @@ -1,56 +0,0 @@ -schema: - query: Query - -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - - T4: - fields: - t4: - type: - name: String - - T5: - fields: - t5: - type: - name: Boolean - - Query: - fields: - test: - type: - name: U - args: - u: - type: - name: U - required: true - http: - url: http://localhost/users/{{args.u}} - -unions: - U1: - types: ["T1", "T2", "T3", "U2"] - U2: - types: ["T3", "T4", "U1"] - U: - types: ["U1", "U2", "T5"] diff --git a/tailcall-fixtures/fixtures/configs/yaml-nested-unions.yaml b/tailcall-fixtures/fixtures/configs/yaml-nested-unions.yaml deleted file mode 100644 index 4672968a04..0000000000 --- a/tailcall-fixtures/fixtures/configs/yaml-nested-unions.yaml +++ /dev/null @@ -1,56 +0,0 @@ -schema: - query: Query - -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - - T4: - fields: - t4: - type: - name: String - - T5: - fields: - t5: - type: - name: Boolean - - Query: - fields: - test: - type: - name: U - args: - u: - type: - name: U - required: true - http: - url: http://localhost/users/{{args.u}} - -unions: - U1: - types: ["T1", "T2", "T3"] - U2: - types: ["T3", "T4"] - U: - types: ["U1", "U2", "T5"] diff --git a/tailcall-fixtures/fixtures/configs/yaml-recursive-input.yaml b/tailcall-fixtures/fixtures/configs/yaml-recursive-input.yaml deleted file mode 100644 index 43ee7c3c72..0000000000 --- a/tailcall-fixtures/fixtures/configs/yaml-recursive-input.yaml +++ /dev/null @@ -1,34 +0,0 @@ -server: - port: 8000 -schema: - query: Query -types: - Bar: - fields: - name: - type: - name: Foo - rec: - type: - name: Bar - - Query: - fields: - bars: - type: - name: String - args: - filter: - type: - name: Bar - graphql: - args: - - key: baz - value: '{{.args.baz}}' - url: http://localhost - name: bars - Foo: - fields: - name: - type: - name: String diff --git a/tailcall-fixtures/fixtures/configs/yaml-union-in-type.yaml b/tailcall-fixtures/fixtures/configs/yaml-union-in-type.yaml deleted file mode 100644 index 66cf2edaae..0000000000 --- a/tailcall-fixtures/fixtures/configs/yaml-union-in-type.yaml +++ /dev/null @@ -1,64 +0,0 @@ -schema: - query: Query - -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - - NU: - fields: - test: - type: - name: String - u: - type: - name: U - - NNU: - fields: - other: - type: - name: Int - new: - type: - name: Boolean - nu: - type: - name: NU - - Query: - fields: - test: - type: - name: U - args: - nu: - type: - name: NU - required: true - nnu: - type: - name: NNU - http: - url: http://localhost/users/{{args.nu.u}} - -unions: - U: - types: ["T1", "T2", "T3"] diff --git a/tailcall-fixtures/fixtures/configs/yaml-union.yaml b/tailcall-fixtures/fixtures/configs/yaml-union.yaml deleted file mode 100644 index 1398fe227c..0000000000 --- a/tailcall-fixtures/fixtures/configs/yaml-union.yaml +++ /dev/null @@ -1,40 +0,0 @@ -schema: - query: Query - -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - - Query: - fields: - test: - type: - name: U - args: - u: - type: - name: U - required: true - http: - url: http://localhost/users/{{args.u}} - -unions: - U: - types: ["T1", "T2", "T3"] diff --git a/tests/core/snapshots/test-enum-empty.md_error.snap b/tests/core/snapshots/test-enum-empty.md_error.snap index 1d843257e5..fa0959164e 100644 --- a/tests/core/snapshots/test-enum-empty.md_error.snap +++ b/tests/core/snapshots/test-enum-empty.md_error.snap @@ -1,10 +1,11 @@ --- source: tests/core/spec.rs expression: errors +snapshot_kind: text --- [ { - "message": "No variants found for enum", + "message": " --> 9:11\n |\n9 | enum Foo {}\n | ^---\n |\n = expected enum_value_definition", "trace": [], "description": null } diff --git a/tests/execution/batching-disabled.md b/tests/execution/batching-disabled.md index d95145be48..5783980497 100644 --- a/tests/execution/batching-disabled.md +++ b/tests/execution/batching-disabled.md @@ -1,66 +1,18 @@ # Batching disabled -```json @config -{ - "server": {}, - "upstream": { - "httpCache": 42, - "batch": { - "maxSize": 100, - "delay": 0, - "headers": [] - } - }, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int", - "required": true - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/{{.args.id}}" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - }, - "username": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server @upstream(httpCache: 42, batch: {maxSize: 100, delay: 0, headers: []}) { + query: Query +} + +type Query { + user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}") +} + +type User { + id: Int + name: String + username: String } ``` diff --git a/tests/execution/batching.md b/tests/execution/batching.md index 648266d6bc..34eb5b6f0d 100644 --- a/tests/execution/batching.md +++ b/tests/execution/batching.md @@ -1,47 +1,17 @@ # Sending a batched graphql request -```json @config -{ - "server": { - "batchRequests": true - }, - "upstream": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server(batchRequests: true) @upstream { + query: Query +} + +type Query { + user: User @http(url: "http://jsonplaceholder.typicode.com/users/1") +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/cache-control.md b/tests/execution/cache-control.md index 130452cd04..c359473e72 100644 --- a/tests/execution/cache-control.md +++ b/tests/execution/cache-control.md @@ -1,62 +1,18 @@ # Sending requests to verify Cache-Control behavior -```json @config -{ - "server": { - "headers": { - "cacheControl": true - } - }, - "upstream": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int" - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users", - "query": [ - { - "key": "id", - "value": "{{.args.id}}" - } - ] - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server(headers: {cacheControl: true}) @upstream { + query: Query +} + +type Query { + user(id: Int): User + @http(url: "http://jsonplaceholder.typicode.com/users", query: [{key: "id", value: "{{.args.id}}"}]) +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/custom-headers.md b/tests/execution/custom-headers.md index 3a0c4f486d..9bf05ba6f4 100644 --- a/tests/execution/custom-headers.md +++ b/tests/execution/custom-headers.md @@ -1,41 +1,12 @@ # Custom Headers -```json @config -{ - "server": { - "headers": { - "custom": [ - { - "key": "x-id", - "value": "1" - }, - { - "key": "x-name", - "value": "John Doe" - } - ] - } - }, - "upstream": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "greet": { - "type": { - "name": "String" - }, - "expr": { - "body": "Hello World!" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server(headers: {custom: [{key: "x-id", value: "1"}, {key: "x-name", value: "John Doe"}]}) @upstream { + query: Query +} + +type Query { + greet: String @expr(body: "Hello World!") } ``` diff --git a/tests/execution/env-value.md b/tests/execution/env-value.md index 15a1ee7862..12eaa4db67 100644 --- a/tests/execution/env-value.md +++ b/tests/execution/env-value.md @@ -1,75 +1,21 @@ # Env value -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Post": { - "fields": { - "body": { - "type": { - "name": "String" - }, - "cache": null - }, - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "title": { - "type": { - "name": "String" - }, - "cache": null - }, - "userId": { - "type": { - "name": "Int", - "required": true - }, - "cache": null - } - }, - "cache": null - }, - "Query": { - "fields": { - "post1": { - "type": { - "name": "Post" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts/{{.env.ID}}" - }, - "cache": null - }, - "post2": { - "type": { - "name": "Post" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts/{{.env.POST_ID}}" - }, - "cache": null - }, - "post3": { - "type": { - "name": "Post" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts/{{.env.NESTED_POST_ID}}" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server { + query: Query +} + +type Post { + body: String + id: Int + title: String + userId: Int! +} + +type Query { + post1: Post @http(url: "http://jsonplaceholder.typicode.com/posts/{{.env.ID}}") + post2: Post @http(url: "http://jsonplaceholder.typicode.com/posts/{{.env.POST_ID}}") + post3: Post @http(url: "http://jsonplaceholder.typicode.com/posts/{{.env.NESTED_POST_ID}}") } ``` diff --git a/tests/execution/https.md b/tests/execution/https.md deleted file mode 100644 index 93b418be13..0000000000 --- a/tests/execution/https.md +++ /dev/null @@ -1,61 +0,0 @@ -# Against a server with HTTPS - -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "firstUser": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } -} -``` - -```yml @mock -- request: - method: GET - url: http://jsonplaceholder.typicode.com/users/1 - response: - status: 200 - body: - id: 1 - name: Leanne Graham -``` - -```yml @test -- method: POST - url: http://localhost:8080/graphql - body: - query: query { firstUser { name } } -``` diff --git a/tests/execution/recursive-types-json.md b/tests/execution/recursive-types-json.md deleted file mode 100644 index 3c3431047e..0000000000 --- a/tests/execution/recursive-types-json.md +++ /dev/null @@ -1,211 +0,0 @@ -# Recursive Type JSON - -```json @config -{ - "$schema": "./.tailcallrc.schema.json", - "upstream": { - "httpCache": 42 - }, - "schema": { - "query": "Query", - "mutation": "Mutation" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - } - } - } - }, - "Mutation": { - "fields": { - "createUser": { - "args": { - "user": { - "type": { - "name": "User" - } - } - }, - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/user", - "method": "POST", - "body": "{{.args.user}}" - } - } - } - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int", - "required": true - } - }, - "name": { - "type": { - "name": "String", - "required": true - } - }, - "connections": { - "type": { - "list": { - "name": "Connection" - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/connections/{{.value.id}}" - } - } - } - }, - "Connection": { - "fields": { - "type": { - "type": { - "name": "String" - } - }, - "user": { - "type": { - "name": "User" - } - } - } - } - } -} -``` - -```yml @mock -- request: - method: GET - url: http://jsonplaceholder.typicode.com/users/1 - response: - status: 200 - body: - id: 1 - name: User1 -- request: - method: GET - url: http://jsonplaceholder.typicode.com/connections/1 - response: - status: 200 - body: - - type: friend - user: - id: 2 - name: User2 - -- request: - method: GET - url: http://jsonplaceholder.typicode.com/connections/2 - response: - status: 200 - body: - - type: friend - user: - id: 3 - name: User3 - - type: coworker - user: - id: 4 - name: User4 - -- request: - method: POST - url: http://jsonplaceholder.typicode.com/user - body: - id: 111 - name: NewUser - connections: - - type: friend - user: - id: 1 - name: User1 - response: - status: 200 - body: - id: 111 - name: NewUser - -- request: - method: GET - url: http://jsonplaceholder.typicode.com/connections/111 - response: - status: 200 - body: - - type: friend - user: - id: 1 - name: User1 -``` - -```yml @test -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user { - name - id - connections { - type - user { - name - id - connections { - user { - name - id - } - } - } - } - } - } - -- method: POST - url: http://localhost:8080/graphql - body: - query: | - mutation { - createUser( - user: { - id: 111, - name: "NewUser", - connections: [ - { - type: "friend" - user: { - id: 1 - name: "User1" - } - } - ] - } - ) { - name - id - connections { - type - user { - name - id - } - } - } - } -``` diff --git a/tests/execution/ref-other-nested.md b/tests/execution/ref-other-nested.md index 9687d9177b..a5d87c839a 100644 --- a/tests/execution/ref-other-nested.md +++ b/tests/execution/ref-other-nested.md @@ -1,69 +1,25 @@ # Ref other nested -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "firstUser": { - "type": { - "name": "User1" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - }, - "User1": { - "fields": { - "user1": { - "type": { - "name": "User2" - }, - "cache": null - } - }, - "cache": null - }, - "User2": { - "fields": { - "user2": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server { + query: Query +} + +type Query { + firstUser: User1 @http(url: "http://jsonplaceholder.typicode.com/users/1") +} + +type User { + id: Int + name: String +} + +type User1 { + user1: User2 +} + +type User2 { + user2: User @http(url: "http://jsonplaceholder.typicode.com/users/1") } ``` diff --git a/tests/execution/request-to-upstream-batching.md b/tests/execution/request-to-upstream-batching.md index c065cbb881..d9de545e0d 100644 --- a/tests/execution/request-to-upstream-batching.md +++ b/tests/execution/request-to-upstream-batching.md @@ -1,68 +1,22 @@ # Batched graphql request to batched upstream query -```json @config -{ - "server": { - "batchRequests": true - }, - "upstream": { - "batch": { - "maxSize": 100, - "delay": 1, - "headers": [] - } - }, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int", - "required": true - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users", - "query": [ - { - "key": "id", - "value": "{{.args.id}}" - } - ], - "batchKey": ["id"] - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server(batchRequests: true) @upstream(batch: {maxSize: 100, delay: 1, headers: []}) { + query: Query +} + +type Query { + user(id: Int!): User + @http( + url: "http://jsonplaceholder.typicode.com/users" + query: [{key: "id", value: "{{.args.id}}"}] + batchKey: ["id"] + ) +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/simple-query.md b/tests/execution/simple-query.md index f706289a95..557c3b7e88 100644 --- a/tests/execution/simple-query.md +++ b/tests/execution/simple-query.md @@ -1,44 +1,17 @@ # Simple query -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "firstUser": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server @upstream { + query: Query +} + +type Query { + firstUser: User @http(url: "http://jsonplaceholder.typicode.com/users/1") +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/test-enum-empty.md b/tests/execution/test-enum-empty.md index 66fbac46c2..c1d3ebcf55 100644 --- a/tests/execution/test-enum-empty.md +++ b/tests/execution/test-enum-empty.md @@ -4,42 +4,14 @@ error: true # test-enum-empty -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "foo": { - "type": { - "name": "Foo" - }, - "args": { - "val": { - "type": { - "name": "String", - "required": true - } - } - }, - "expr": { - "body": "{{.args.val}}" - }, - "cache": null, - "protected": null - } - }, - "protected": null - } - }, - "enums": { - "Foo": { - "variants": [], - "doc": null - } - } +```graphql @config +schema @server { + query: Query } + +type Query { + foo(val: String!): Foo @expr(body: "{{.args.val}}") +} + +enum Foo {} ``` diff --git a/tests/execution/test-interface-from-json.md b/tests/execution/test-interface-from-json.md deleted file mode 100644 index 9d2e25dbb6..0000000000 --- a/tests/execution/test-interface-from-json.md +++ /dev/null @@ -1,47 +0,0 @@ -# Interfaces defined in json - -```json @config -{ - "schema": { - "query": "Query" - }, - "types": { - "IA": { - "fields": { - "a": { - "type": { - "name": "String" - } - } - } - }, - "B": { - "implements": ["IA"], - "fields": { - "a": { - "type": { - "name": "String" - } - }, - "b": { - "type": { - "name": "String" - } - } - } - }, - "Query": { - "fields": { - "bar": { - "type": { - "name": "B" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/posts" - } - } - } - } - } -} -``` diff --git a/tests/execution/test-static-value.md b/tests/execution/test-static-value.md deleted file mode 100644 index 960a74700e..0000000000 --- a/tests/execution/test-static-value.md +++ /dev/null @@ -1,62 +0,0 @@ -# Static value - -```json @config -{ - "server": {}, - "upstream": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "firstUser": { - "type": { - "name": "User" - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/1" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } -} -``` - -```yml @mock -- request: - method: GET - url: http://jsonplaceholder.typicode.com/users/1 - response: - status: 200 - body: - id: 1 - name: Leanne Graham -``` - -```yml @test -- method: POST - url: http://localhost:8080/graphql - body: - query: query { firstUser { name } } -``` diff --git a/tests/execution/upstream-batching.md b/tests/execution/upstream-batching.md index e65c735567..b911bad51a 100644 --- a/tests/execution/upstream-batching.md +++ b/tests/execution/upstream-batching.md @@ -1,65 +1,22 @@ # Sending requests to be batched by the upstream server -```json @config -{ - "server": {}, - "upstream": { - "batch": { - "maxSize": 100, - "delay": 1, - "headers": [] - } - }, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int" - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users", - "query": [ - { - "key": "id", - "value": "{{.args.id}}" - } - ], - "batchKey": ["id"] - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server @upstream(batch: {maxSize: 100, delay: 1, headers: []}) { + query: Query +} + +type Query { + user(id: Int): User + @http( + url: "http://jsonplaceholder.typicode.com/users" + query: [{key: "id", value: "{{.args.id}}"}] + batchKey: ["id"] + ) +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/with-args-url.md b/tests/execution/with-args-url.md index ccb98f2cc0..0fa10d9b4b 100644 --- a/tests/execution/with-args-url.md +++ b/tests/execution/with-args-url.md @@ -1,52 +1,17 @@ # With args URL -```json @config -{ - "server": {}, - "schema": { - "query": "Query" - }, - "types": { - "Query": { - "fields": { - "user": { - "type": { - "name": "User" - }, - "args": { - "id": { - "type": { - "name": "Int", - "required": true - } - } - }, - "http": { - "url": "http://jsonplaceholder.typicode.com/users/{{.args.id}}" - }, - "cache": null - } - }, - "cache": null - }, - "User": { - "fields": { - "id": { - "type": { - "name": "Int" - }, - "cache": null - }, - "name": { - "type": { - "name": "String" - }, - "cache": null - } - }, - "cache": null - } - } +```graphql @config +schema @server { + query: Query +} + +type Query { + user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}") +} + +type User { + id: Int + name: String } ``` diff --git a/tests/execution/yaml-nested-unions.md b/tests/execution/yaml-nested-unions.md index 2f3dee7431..59b939c0a3 100644 --- a/tests/execution/yaml-nested-unions.md +++ b/tests/execution/yaml-nested-unions.md @@ -1,60 +1,36 @@ # Using union types inside other union types -```yml @config -schema: +```graphql @config +schema { query: Query +} -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - - T4: - fields: - t4: - type: - name: String - - T5: - fields: - t5: - type: - name: Boolean - - Query: - fields: - test: - type: - name: U - args: - u: - type: - name: U - required: true - http: - url: http://localhost/users/{{args.u}} - -unions: - U1: - types: ["T1", "T2", "T3"] - U2: - types: ["T3", "T4"] - U: - types: ["U1", "U2", "T5"] +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +type T4 { + t4: String +} + +type T5 { + t5: Boolean +} + +union U1 = T1 | T2 | T3 +union U2 = T3 | T4 +union U = U1 | U2 | T5 + +type Query { + test(u: U!): U @http(url: "http://localhost/users/{{args.u}}") +} ``` diff --git a/tests/execution/yaml-union-in-type.md b/tests/execution/yaml-union-in-type.md index 2074c69945..8a56322500 100644 --- a/tests/execution/yaml-union-in-type.md +++ b/tests/execution/yaml-union-in-type.md @@ -1,68 +1,37 @@ # Using Union types inside usual type -```yml @config -schema: +```graphql @config +schema { query: Query +} -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true +type T1 { + t1: String +} - NU: - fields: - test: - type: - name: String - u: - type: - name: U +type T2 { + t2: Int +} - NNU: - fields: - other: - type: - name: Int - new: - type: - name: Boolean - nu: - type: - name: NU +type T3 { + t3: Boolean + t33: Float! +} - Query: - fields: - test: - type: - name: U - args: - nu: - type: - name: NU - required: true - nnu: - type: - name: NNU - http: - url: http://localhost/users/{{args.nu.u}} +type NU { + test: String + u: U +} -unions: - U: - types: ["T1", "T2", "T3"] +type NNU { + other: Int + new: Boolean + nu: NU +} + +union U = T1 | T2 | T3 + +type Query { + test(nu: NU!, nnu: NNU): U @http(url: "http://localhost/users/{{args.nu.u}}") +} ``` diff --git a/tests/execution/yaml-union.md b/tests/execution/yaml-union.md index e15d9eeec9..ec31ed9073 100644 --- a/tests/execution/yaml-union.md +++ b/tests/execution/yaml-union.md @@ -1,54 +1,34 @@ # Using Union types in yaml config -```yml @config -schema: +```graphql @config +schema { query: Query +} -types: - T1: - fields: - t1: - type: - name: String - T2: - fields: - t2: - type: - name: Int - T3: - fields: - t3: - type: - name: Boolean - t33: - type: - name: Float - required: true - NU: - fields: - u: - type: - name: U - - NNU: - fields: - nu: - type: - name: NU - Query: - fields: - test: - type: - name: U - args: - u: - type: - name: U - required: true - http: - url: http://localhost/users/{{args.u}}/ - -unions: - U: - types: ["T1", "T2", "T3"] +type T1 { + t1: String +} + +type T2 { + t2: Int +} + +type T3 { + t3: Boolean + t33: Float! +} + +type NU { + u: U +} + +type NNU { + nu: NU +} + +union U = T1 | T2 | T3 + +type Query { + test(u: U!): U @http(url: "http://localhost/users/{{args.u}}/") +} ``` diff --git a/tests/graphql_spec.graphql b/tests/graphql_spec.graphql deleted file mode 100644 index 6f57f54ad0..0000000000 --- a/tests/graphql_spec.graphql +++ /dev/null @@ -1 +0,0 @@ -directive @error(message: String!, trace: [String!]!, description: String) repeatable on OBJECT