From 4a9063f755b72786c3c5928b2fa74cf1aa935129 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Thu, 5 Aug 2021 11:25:31 -0500 Subject: http-api: T2768: add README.graphql --- src/services/api/graphql/README.graphql | 112 ++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/services/api/graphql/README.graphql (limited to 'src') diff --git a/src/services/api/graphql/README.graphql b/src/services/api/graphql/README.graphql new file mode 100644 index 000000000..8414e795a --- /dev/null +++ b/src/services/api/graphql/README.graphql @@ -0,0 +1,112 @@ + +Example using GraphQL mutations to configure a DHCP server: + +This assumes that the http-api is running: + +'set service https api' + +One can configure an address on an interface, and configure the DHCP server +to run with that address as default router by requesting these 'mutations': + +mutation { + createInterfaceEthernet (data: {interface: "eth1", + address: "192.168.0.1/24", + description: "BOB"}) { + success + errors + data { + address + } + } +} + +mutation { + createDhcpServer(data: {sharedNetworkName: "BOB", + subnet: "192.168.0.0/24", + defaultRouter: "192.168.0.1", + dnsServer: "192.168.0.1", + domainName: "vyos.net", + lease: 86400, + range: 0, + start: "192.168.0.9", + stop: "192.168.0.254", + dnsForwardingAllowFrom: "192.168.0.0/24", + dnsForwardingCacheSize: 0, + dnsForwardingListenAddress: "192.168.0.1"}) { + success + errors + data { + defaultRouter + } + } +} + +These requests can be set in the GraphQL playground, or made with curl: + +curl -k -H 'Content-Type: application/json' -d '{"query": "{hello}"}' https://{{ host_address }}/graphql + +replacing the query with the above mutations as JSON. + +What's here: + +services +├── api +│   └── graphql +│   ├── graphql +│   │   ├── directives.py +│   │   ├── __init__.py +│   │   ├── mutations.py +│   │   └── schema +│   │   ├── dhcp_server.graphql +│   │   ├── interface_ethernet.graphql +│   │   └── schema.graphql +│   ├── recipes +│   │   ├── dhcp_server.py +│   │   ├── __init__.py +│   │   ├── interface_ethernet.py +│   │   ├── recipe.py +│   │   └── templates +│   │   ├── dhcp_server.tmpl +│   │   └── interface_ethernet.tmpl +│   └── state.py +├── vyos-configd +├── vyos-hostsd +└── vyos-http-api-server + +The GraphQL library that we are using, Ariadne, advertises itself as a +'schema-first' implementation: define the schema; define resolvers +(handlers) for declared Query and Mutation types (Subscription types are not +currently used). + +In the current approach to a high-level API, we consider the +Jinja2-templated collection of configuration mode 'set'/'delete' commands as +the Ur-data; the GraphQL schema is produced from those files, located in +'api/recipes/templates'. + +Resolvers for the schema Mutation fields are dynamically generated using a +'directive' added to the respective schema field. The directive, +'@generate', is handled by the class 'DataDirective' in +'api/graphql/directives.py', which calls the 'make_resolver' function in +'api/graphql/mutations.py'; the produced resolver calls the appropriate +wrapper in 'api/recipes', with base class doing the (overridable) +configuration steps of calling all defined 'set'/'delete' commands. + +Integrating the above with vyos-http-api-server is ~10 lines of code. + +What needs to be done: + +• automate generation of schema and wrappers from templated configuration +commands + +• investigate whether the inversion of control provided by the named +wrappers in 'api/recipes' is sufficient for use cases which need to modify +data + +• encapsulate the manipulation of 'canonical names' which transforms the +prefixed camel-case schema names to various snake-case file/function names + +• consider mechanism for migration of templates: offline vs. on-the-fly + +• define the naming convention for those schema fields that refer to +configuration mode parameters: e.g. how much of the path is needed as prefix +to uniquely define the term -- cgit v1.2.3