synthra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
# GraphQL Federation Export
|
|
2
|
+
|
|
3
|
+
FakeDataDSL can export your schemas to **GraphQL Federation 2.0** compatible SDL, perfect for microservices architectures using Apollo Federation, Netflix DGS, or other federated GraphQL implementations.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Export single schema
|
|
9
|
+
fake_data_dsl export schemas/user.dsl -f graphql-federation -o user.graphql
|
|
10
|
+
|
|
11
|
+
# Export all schemas
|
|
12
|
+
fake_data_dsl export schemas/ --all -f graphql-federation -o schema.graphql
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# Ruby API
|
|
17
|
+
schema = FakeDataDSL.load("schemas/user.dsl")
|
|
18
|
+
graphql = FakeDataDSL::Export::GraphQLFederation.new(schema).export
|
|
19
|
+
|
|
20
|
+
puts graphql
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Basic Usage
|
|
24
|
+
|
|
25
|
+
### Single Schema Export
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Input schema (user.dsl)
|
|
29
|
+
# User:
|
|
30
|
+
# id: uuid
|
|
31
|
+
# name: name
|
|
32
|
+
# email: email
|
|
33
|
+
# role: enum(user, admin, moderator)
|
|
34
|
+
# active: boolean
|
|
35
|
+
# created_at: timestamp
|
|
36
|
+
|
|
37
|
+
schema = FakeDataDSL.load("schemas/user.dsl")
|
|
38
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema)
|
|
39
|
+
puts exporter.export
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Output:
|
|
43
|
+
|
|
44
|
+
```graphql
|
|
45
|
+
extend schema
|
|
46
|
+
@link(url: "https://specs.apollo.dev/federation/v2.0")
|
|
47
|
+
|
|
48
|
+
type User @key(fields: "id") {
|
|
49
|
+
id: ID!
|
|
50
|
+
name: String!
|
|
51
|
+
email: String!
|
|
52
|
+
role: UserRole!
|
|
53
|
+
active: Boolean!
|
|
54
|
+
created_at: DateTime!
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
enum UserRole {
|
|
58
|
+
USER
|
|
59
|
+
ADMIN
|
|
60
|
+
MODERATOR
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
extend type Query {
|
|
64
|
+
user(id: ID!): User
|
|
65
|
+
users(first: Int, after: String): UserConnection!
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type UserConnection {
|
|
69
|
+
edges: [UserEdge!]!
|
|
70
|
+
pageInfo: PageInfo!
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type UserEdge {
|
|
74
|
+
node: User!
|
|
75
|
+
cursor: String!
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type PageInfo {
|
|
79
|
+
hasNextPage: Boolean!
|
|
80
|
+
hasPreviousPage: Boolean!
|
|
81
|
+
startCursor: String
|
|
82
|
+
endCursor: String
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Multiple Schemas
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# Export multiple schemas as one federated graph
|
|
90
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(
|
|
91
|
+
FakeDataDSL.load("schemas/user.dsl"),
|
|
92
|
+
FakeDataDSL.load("schemas/order.dsl"),
|
|
93
|
+
FakeDataDSL.load("schemas/product.dsl")
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
puts exporter.export
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Federation Directives
|
|
100
|
+
|
|
101
|
+
### @key Directive
|
|
102
|
+
|
|
103
|
+
Entity keys are automatically inferred from `id` fields or fields marked with `@key`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
# In DSL
|
|
107
|
+
User:
|
|
108
|
+
id: uuid @key
|
|
109
|
+
email: email @key # Additional key
|
|
110
|
+
|
|
111
|
+
# Output
|
|
112
|
+
type User @key(fields: "id") @key(fields: "email") {
|
|
113
|
+
id: ID!
|
|
114
|
+
email: String!
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### @external and @provides
|
|
119
|
+
|
|
120
|
+
For cross-service references:
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
# In DSL
|
|
124
|
+
Order:
|
|
125
|
+
id: uuid
|
|
126
|
+
user_id: Ref(User.id) # Reference to User service
|
|
127
|
+
items: array(OrderItem, 1..10)
|
|
128
|
+
total: money
|
|
129
|
+
|
|
130
|
+
# Configure federation
|
|
131
|
+
FakeDataDSL::Export::GraphQLFederation.configure do |config|
|
|
132
|
+
config.external_types = ["User"]
|
|
133
|
+
config.provides = {
|
|
134
|
+
"Order" => { "user" => "id name email" }
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Output:
|
|
140
|
+
|
|
141
|
+
```graphql
|
|
142
|
+
type Order @key(fields: "id") {
|
|
143
|
+
id: ID!
|
|
144
|
+
user: User! @provides(fields: "id name email")
|
|
145
|
+
items: [OrderItem!]!
|
|
146
|
+
total: Float!
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
type User @key(fields: "id", resolvable: false) @external {
|
|
150
|
+
id: ID!
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### @shareable
|
|
155
|
+
|
|
156
|
+
Mark types as shareable across services:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
# In DSL
|
|
160
|
+
Address:
|
|
161
|
+
@shareable
|
|
162
|
+
street: text
|
|
163
|
+
city: city
|
|
164
|
+
country: country
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Output:
|
|
168
|
+
|
|
169
|
+
```graphql
|
|
170
|
+
type Address @shareable {
|
|
171
|
+
street: String!
|
|
172
|
+
city: String!
|
|
173
|
+
country: String!
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Subgraph Configuration
|
|
178
|
+
|
|
179
|
+
### Service Definition
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
183
|
+
service_name: "users-service",
|
|
184
|
+
service_url: "https://users.example.com/graphql",
|
|
185
|
+
version: "2.0"
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Multiple Subgraphs
|
|
190
|
+
|
|
191
|
+
Generate separate files for each subgraph:
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
# Define subgraph boundaries
|
|
195
|
+
subgraphs = {
|
|
196
|
+
"users" => ["User", "Profile"],
|
|
197
|
+
"orders" => ["Order", "OrderItem"],
|
|
198
|
+
"products" => ["Product", "Category"]
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
subgraphs.each do |name, types|
|
|
202
|
+
schemas = types.map { |t| FakeDataDSL.schema(t) }
|
|
203
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(*schemas,
|
|
204
|
+
service_name: "#{name}-service"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
File.write("subgraphs/#{name}.graphql", exporter.export)
|
|
208
|
+
end
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Type Mapping
|
|
212
|
+
|
|
213
|
+
### DSL to GraphQL Types
|
|
214
|
+
|
|
215
|
+
| DSL Type | GraphQL Type |
|
|
216
|
+
|----------|--------------|
|
|
217
|
+
| `uuid` | `ID!` |
|
|
218
|
+
| `text`, `name`, `email` | `String!` |
|
|
219
|
+
| `number` | `Int!` |
|
|
220
|
+
| `float`, `money` | `Float!` |
|
|
221
|
+
| `boolean` | `Boolean!` |
|
|
222
|
+
| `date` | `Date!` |
|
|
223
|
+
| `timestamp` | `DateTime!` |
|
|
224
|
+
| `enum(...)` | Custom Enum |
|
|
225
|
+
| `array(...)` | `[Type!]!` |
|
|
226
|
+
| `optional` (`?`) | Nullable |
|
|
227
|
+
| `json` | `JSON` (custom scalar) |
|
|
228
|
+
|
|
229
|
+
### Custom Scalars
|
|
230
|
+
|
|
231
|
+
```ruby
|
|
232
|
+
FakeDataDSL::Export::GraphQLFederation.configure do |config|
|
|
233
|
+
config.custom_scalars = {
|
|
234
|
+
"date" => "Date",
|
|
235
|
+
"timestamp" => "DateTime",
|
|
236
|
+
"json" => "JSON",
|
|
237
|
+
"money" => "BigDecimal",
|
|
238
|
+
"url" => "URL",
|
|
239
|
+
"email" => "Email"
|
|
240
|
+
}
|
|
241
|
+
end
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Output includes scalar definitions:
|
|
245
|
+
|
|
246
|
+
```graphql
|
|
247
|
+
scalar Date
|
|
248
|
+
scalar DateTime
|
|
249
|
+
scalar JSON
|
|
250
|
+
scalar BigDecimal
|
|
251
|
+
scalar URL
|
|
252
|
+
scalar Email
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Mutations
|
|
256
|
+
|
|
257
|
+
### Auto-Generated Mutations
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
261
|
+
generate_mutations: true
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Output:
|
|
266
|
+
|
|
267
|
+
```graphql
|
|
268
|
+
extend type Mutation {
|
|
269
|
+
createUser(input: CreateUserInput!): User!
|
|
270
|
+
updateUser(id: ID!, input: UpdateUserInput!): User!
|
|
271
|
+
deleteUser(id: ID!): Boolean!
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
input CreateUserInput {
|
|
275
|
+
name: String!
|
|
276
|
+
email: String!
|
|
277
|
+
role: UserRole
|
|
278
|
+
active: Boolean
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
input UpdateUserInput {
|
|
282
|
+
name: String
|
|
283
|
+
email: String
|
|
284
|
+
role: UserRole
|
|
285
|
+
active: Boolean
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Custom Mutations
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
# In DSL with @mutation annotation
|
|
293
|
+
User:
|
|
294
|
+
id: uuid
|
|
295
|
+
name: name
|
|
296
|
+
email: email
|
|
297
|
+
|
|
298
|
+
@mutations
|
|
299
|
+
create: CreateUser(name!, email!, role?)
|
|
300
|
+
update: UpdateUser(id!, name?, email?, role?)
|
|
301
|
+
deactivate: DeactivateUser(id!, reason?)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Subscriptions
|
|
305
|
+
|
|
306
|
+
```ruby
|
|
307
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
308
|
+
generate_subscriptions: true
|
|
309
|
+
)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Output:
|
|
313
|
+
|
|
314
|
+
```graphql
|
|
315
|
+
extend type Subscription {
|
|
316
|
+
userCreated: User!
|
|
317
|
+
userUpdated(id: ID): User!
|
|
318
|
+
userDeleted: ID!
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Entity Resolution
|
|
323
|
+
|
|
324
|
+
### _entities Query
|
|
325
|
+
|
|
326
|
+
Federation requires an `_entities` query for entity resolution:
|
|
327
|
+
|
|
328
|
+
```ruby
|
|
329
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
330
|
+
include_entities_query: true # default: true
|
|
331
|
+
)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Output:
|
|
335
|
+
|
|
336
|
+
```graphql
|
|
337
|
+
union _Entity = User | Order | Product
|
|
338
|
+
|
|
339
|
+
type Query {
|
|
340
|
+
_entities(representations: [_Any!]!): [_Entity]!
|
|
341
|
+
_service: _Service!
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
type _Service {
|
|
345
|
+
sdl: String!
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
scalar _Any
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Interfaces and Unions
|
|
352
|
+
|
|
353
|
+
### Interfaces
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
# In DSL
|
|
357
|
+
Node:
|
|
358
|
+
@interface
|
|
359
|
+
id: uuid
|
|
360
|
+
|
|
361
|
+
User < Node:
|
|
362
|
+
name: name
|
|
363
|
+
email: email
|
|
364
|
+
|
|
365
|
+
Product < Node:
|
|
366
|
+
title: text
|
|
367
|
+
price: money
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Output:
|
|
371
|
+
|
|
372
|
+
```graphql
|
|
373
|
+
interface Node {
|
|
374
|
+
id: ID!
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
type User implements Node @key(fields: "id") {
|
|
378
|
+
id: ID!
|
|
379
|
+
name: String!
|
|
380
|
+
email: String!
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
type Product implements Node @key(fields: "id") {
|
|
384
|
+
id: ID!
|
|
385
|
+
title: String!
|
|
386
|
+
price: Float!
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Unions
|
|
391
|
+
|
|
392
|
+
```ruby
|
|
393
|
+
# In DSL
|
|
394
|
+
SearchResult:
|
|
395
|
+
@union User | Product | Order
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Output:
|
|
399
|
+
|
|
400
|
+
```graphql
|
|
401
|
+
union SearchResult = User | Product | Order
|
|
402
|
+
|
|
403
|
+
extend type Query {
|
|
404
|
+
search(query: String!): [SearchResult!]!
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Pagination
|
|
409
|
+
|
|
410
|
+
### Relay-Style Connections
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
414
|
+
pagination_style: :relay # default
|
|
415
|
+
)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Output:
|
|
419
|
+
|
|
420
|
+
```graphql
|
|
421
|
+
type UserConnection {
|
|
422
|
+
edges: [UserEdge!]!
|
|
423
|
+
pageInfo: PageInfo!
|
|
424
|
+
totalCount: Int!
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
type UserEdge {
|
|
428
|
+
node: User!
|
|
429
|
+
cursor: String!
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Offset Pagination
|
|
434
|
+
|
|
435
|
+
```ruby
|
|
436
|
+
exporter = FakeDataDSL::Export::GraphQLFederation.new(schema,
|
|
437
|
+
pagination_style: :offset
|
|
438
|
+
)
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Output:
|
|
442
|
+
|
|
443
|
+
```graphql
|
|
444
|
+
type UserList {
|
|
445
|
+
items: [User!]!
|
|
446
|
+
total: Int!
|
|
447
|
+
offset: Int!
|
|
448
|
+
limit: Int!
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
extend type Query {
|
|
452
|
+
users(offset: Int, limit: Int): UserList!
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## CLI Options
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
fake_data_dsl export [SCHEMA_PATH] -f graphql-federation [OPTIONS]
|
|
460
|
+
|
|
461
|
+
Options:
|
|
462
|
+
-o, --output PATH Output file path
|
|
463
|
+
--service-name NAME Service name for subgraph
|
|
464
|
+
--service-url URL Service URL for federation
|
|
465
|
+
--federation-version VER Federation version (1 or 2, default: 2)
|
|
466
|
+
--no-mutations Don't generate mutations
|
|
467
|
+
--no-subscriptions Don't generate subscriptions
|
|
468
|
+
--no-pagination Don't generate connection types
|
|
469
|
+
--pagination-style STYLE Pagination style (relay or offset)
|
|
470
|
+
--external-types TYPES Comma-separated external type names
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Examples:
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Basic export
|
|
477
|
+
fake_data_dsl export schemas/ -f graphql-federation -o schema.graphql
|
|
478
|
+
|
|
479
|
+
# With service configuration
|
|
480
|
+
fake_data_dsl export schemas/user.dsl -f graphql-federation \
|
|
481
|
+
--service-name users \
|
|
482
|
+
--service-url https://users.api.example.com/graphql \
|
|
483
|
+
-o users.graphql
|
|
484
|
+
|
|
485
|
+
# Minimal export (no mutations/subscriptions)
|
|
486
|
+
fake_data_dsl export schemas/ -f graphql-federation \
|
|
487
|
+
--no-mutations --no-subscriptions \
|
|
488
|
+
-o types-only.graphql
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## API Reference
|
|
492
|
+
|
|
493
|
+
### GraphQLFederation.new
|
|
494
|
+
|
|
495
|
+
```ruby
|
|
496
|
+
FakeDataDSL::Export::GraphQLFederation.new(*schemas, options = {})
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Parameters:**
|
|
500
|
+
- `schemas` - One or more Schema objects
|
|
501
|
+
- `options[:service_name]` - Subgraph service name
|
|
502
|
+
- `options[:service_url]` - Subgraph service URL
|
|
503
|
+
- `options[:version]` - Federation version ("1" or "2")
|
|
504
|
+
- `options[:generate_mutations]` - Include mutations (default: false)
|
|
505
|
+
- `options[:generate_subscriptions]` - Include subscriptions (default: false)
|
|
506
|
+
- `options[:pagination_style]` - :relay or :offset
|
|
507
|
+
- `options[:include_entities_query]` - Include _entities (default: true)
|
|
508
|
+
- `options[:external_types]` - Array of external type names
|
|
509
|
+
- `options[:custom_scalars]` - Hash of DSL type => GraphQL scalar
|
|
510
|
+
|
|
511
|
+
### GraphQLFederation#export
|
|
512
|
+
|
|
513
|
+
```ruby
|
|
514
|
+
exporter.export
|
|
515
|
+
# => String containing complete GraphQL SDL
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### GraphQLFederation#export_to_file
|
|
519
|
+
|
|
520
|
+
```ruby
|
|
521
|
+
exporter.export_to_file("schema.graphql")
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## Integration Examples
|
|
525
|
+
|
|
526
|
+
### Apollo Router
|
|
527
|
+
|
|
528
|
+
```yaml
|
|
529
|
+
# supergraph.yaml
|
|
530
|
+
federation_version: 2
|
|
531
|
+
subgraphs:
|
|
532
|
+
users:
|
|
533
|
+
routing_url: https://users.example.com/graphql
|
|
534
|
+
schema:
|
|
535
|
+
file: ./users.graphql # Generated by FakeDataDSL
|
|
536
|
+
orders:
|
|
537
|
+
routing_url: https://orders.example.com/graphql
|
|
538
|
+
schema:
|
|
539
|
+
file: ./orders.graphql
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Netflix DGS
|
|
543
|
+
|
|
544
|
+
```kotlin
|
|
545
|
+
// The generated schema works with DGS
|
|
546
|
+
@DgsComponent
|
|
547
|
+
class UserDataFetcher {
|
|
548
|
+
@DgsQuery
|
|
549
|
+
fun user(@InputArgument id: String): User {
|
|
550
|
+
// Resolver implementation
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
@DgsEntityFetcher(name = "User")
|
|
554
|
+
fun user(values: Map<String, Any>): User {
|
|
555
|
+
// Entity resolver for federation
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Apollo Server
|
|
561
|
+
|
|
562
|
+
```javascript
|
|
563
|
+
// The generated schema works with Apollo Server
|
|
564
|
+
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
565
|
+
import { readFileSync } from 'fs';
|
|
566
|
+
|
|
567
|
+
const typeDefs = gql(readFileSync('./user.graphql', 'utf8'));
|
|
568
|
+
|
|
569
|
+
const server = new ApolloServer({
|
|
570
|
+
schema: buildSubgraphSchema({ typeDefs, resolvers })
|
|
571
|
+
});
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## Best Practices
|
|
575
|
+
|
|
576
|
+
### 1. One Entity Per Service
|
|
577
|
+
|
|
578
|
+
```ruby
|
|
579
|
+
# Good: Clear ownership
|
|
580
|
+
# users-service owns User, Profile
|
|
581
|
+
# orders-service owns Order, OrderItem
|
|
582
|
+
|
|
583
|
+
# Avoid: Shared ownership
|
|
584
|
+
# Both services define User (unless @shareable)
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### 2. Use @key Thoughtfully
|
|
588
|
+
|
|
589
|
+
```ruby
|
|
590
|
+
# Good: Natural keys
|
|
591
|
+
User:
|
|
592
|
+
id: uuid @key
|
|
593
|
+
email: email @key # Secondary lookup
|
|
594
|
+
|
|
595
|
+
# Avoid: Composite keys when unnecessary
|
|
596
|
+
User:
|
|
597
|
+
id: uuid @key
|
|
598
|
+
tenant_id: uuid @key # Only if truly needed
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### 3. Keep Schemas Aligned
|
|
602
|
+
|
|
603
|
+
```ruby
|
|
604
|
+
# Use the DSL as source of truth
|
|
605
|
+
# Generate GraphQL from DSL, not the other way around
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
## Troubleshooting
|
|
609
|
+
|
|
610
|
+
### Missing @key Directive
|
|
611
|
+
|
|
612
|
+
```ruby
|
|
613
|
+
# Make sure id field exists or add @key annotation
|
|
614
|
+
User:
|
|
615
|
+
id: uuid # Auto-detected as key
|
|
616
|
+
|
|
617
|
+
# Or explicit
|
|
618
|
+
User:
|
|
619
|
+
user_id: uuid @key # Explicit key
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Enum Name Conflicts
|
|
623
|
+
|
|
624
|
+
```ruby
|
|
625
|
+
# Use namespaced enums
|
|
626
|
+
User:
|
|
627
|
+
status: enum(active, inactive) @enum_name(UserStatus)
|
|
628
|
+
|
|
629
|
+
Product:
|
|
630
|
+
status: enum(draft, published) @enum_name(ProductStatus)
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Circular References
|
|
634
|
+
|
|
635
|
+
```ruby
|
|
636
|
+
# Federation handles this via external types
|
|
637
|
+
# User service:
|
|
638
|
+
User:
|
|
639
|
+
orders: array(Ref(Order))
|
|
640
|
+
|
|
641
|
+
# Order service:
|
|
642
|
+
Order:
|
|
643
|
+
user: Ref(User) @external
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## See Also
|
|
647
|
+
|
|
648
|
+
- [GraphQL Export](GRAPHQL_EXPORT.md) - Standard GraphQL (non-federated)
|
|
649
|
+
- [OpenAPI Export](OPENAPI_EXPORT.md)
|
|
650
|
+
- [Protobuf Export](PROTOBUF_EXPORT.md)
|
|
651
|
+
- [Type Reference](type_reference.md)
|