summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2021-08-05 11:25:31 -0500
committerJohn Estabrook <jestabro@vyos.io>2021-11-07 15:21:50 -0600
commit9756b870d503eab00714b21c66bf30de47878f6e (patch)
tree2daa03098c0bcc7adcde18da02fd5fdfe988b501
parentf87f6c249535453b8bd3718dc7cdc84dcbbdbe13 (diff)
downloadvyos-1x-9756b870d503eab00714b21c66bf30de47878f6e.tar.gz
vyos-1x-9756b870d503eab00714b21c66bf30de47878f6e.zip
http-api: T2768: add README.graphql
(cherry picked from commit 5b69aad5bfe1fd1dfc51afb1d4b6323028009deb)
-rw-r--r--src/services/api/graphql/README.graphql116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/services/api/graphql/README.graphql b/src/services/api/graphql/README.graphql
new file mode 100644
index 000000000..a04138010
--- /dev/null
+++ b/src/services/api/graphql/README.graphql
@@ -0,0 +1,116 @@
+
+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'
+in the GraphQL playground:
+
+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
+ }
+ }
+}
+
+The GraphQL playground will be found at:
+
+https://{{ host_address }}/graphql
+
+An equivalent curl command to the first example above would be:
+
+curl -k 'https://192.168.100.168/graphql' -H 'Content-Type: application/json' --data-binary '{"query": "mutation {createInterfaceEthernet (data: {interface: \"eth1\", address: \"192.168.0.1/24\", description: \"BOB\"}) {success errors data {address}}}"}'
+
+Note that the 'mutation' term is prefaced by 'query' in the curl command.
+
+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/graphql/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/graphql/directives.py', which calls the 'make_resolver' function in
+'api/graphql/graphql/mutations.py'; the produced resolver calls the appropriate
+wrapper in 'api/graphql/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 subclassing provided by the named wrappers in
+'api/graphql/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