cppgraphqlgen

C++ GraphQL schema service generator

MIT License

Stars
323
Committers
16
cppgraphqlgen - Version 4.0 Release Candidate

Published by wravery almost 3 years ago

This contains all of the planned code changes for 4.0 discussed in #172. I tested with local changes to the https://github.com/microsoft/vcpkg port file and https:://github.com/microsoft/gqlmapi. I still need to update the documentation before I merge into main and make an official release. Until then, comparing the next branch of gqlmapi to main can give you a preview of some of the changes.

What's Changed

Full Changelog: https://github.com/microsoft/cppgraphqlgen/compare/v3.6.0...v4.0.0-rc

cppgraphqlgen - Generate strongly typed consumers with clientgen

Published by wravery over 3 years ago

After a lot of refactoring, I added a clientgen utility and graphqlclient support library to build strongly typed clients from static request documents, similar to the way that client frameworks like Apollo or Relay generate types for the variables and responses.

Since clientgen parses and validates the request at code generation time, in addition to the text of the request document returned by GetRequestText, it will also return a pre-parsed and pre-validated request AST (Abstract Syntax Tree) from GetRequestObject. There's a new benchmark program called client_benchmark in the samples directory, which replaces the parse/validate step with the pre-built request AST from GetRequestObject, and it replaces JSON serialization with parsing directly into the strongly typed response object. Your mileage may vary, on my fast Intel desktop running Windows, it had a little over 2x the single-threaded throughput of parsing and validating plus JSON serialization, and on a low-powered ARM64 Linux laptop it had just under 2x the throughput. Either way, the bulk of the savings came from not needing to parse and validate the queries in the loop, on the faster machine serializing to the strongly typed object was slightly faster and on the other serializing to JSON was slightly faster.

cppgraphqlgen - Rename library targets and update to PEGTL 3.2.0

Published by wravery almost 4 years ago

The naming of graphqlservice_nointrospection vs. graphqlservice was confusing, although it did mean that CMake builds which linked against graphqlservice kept working without modification. It is still source compatible, but I decided to break backwards compatibility with CMake builds by renaming graphqlservice_nointrospection back to graphqlservice, and graphqlservice (which depends on that and just adds Introspection support) to graphqlintrospection.

If you use CMake and you want to include Introspection support, add cppgraphqlgen::graphqlintrospection to your target_link_libraries. You can also just replace cppgraphqlgen::graphqlservice with that, it exports a public link dependency on graphqlservice. If you do not use CMake in your own project, but you still built/installed cppgraphqlgen using CMake (including using a package manager like vcpkg), then you need to link against both target libraries.

If you do not want Introspection support, you can regenerate your schema implementation with schemagen --no-introspection, and instead of linking against graphqlintrospection, just link against graphqlservice.

PEGTL released 3.2.0 which includes the fix for the demangle namespace, so cppgraphqlgen no longer depends on a pre-release version of PEGTL or a preprocessor workaround to redeclare demangle in the expected namespace with 3.1.0.

cppgraphqlgen - Add version information and check compatibility with library version in headers

Published by wravery almost 4 years ago

  • There's a new internal/Version.h generated header, and on Windows, there are generated res/*.rc files with VERSION_INFO meta-data for schemagen.exe and all of the DLLs.
  • schemagen has a new --version flag which reports the project version.
  • schemagen --introspection no longer overrides or changes the defaults for the target header or source directories, CMake copies them to the source tree if they change.
  • schemagen generates static_asserts in the generated files which will break the build if you try to build with a different major.minor version than what's in internal/Version.h. If you don't automatically regenerate with schemagen as part of your build, this should help keep manually generated files in synch with corresponding changes in the library which may depend on re-running the generator.
  • I added all of the files generated with CMake to the repo and tidied up the dependencies and logic which updates the sources after generation. Unless you suppress it with GRAPHQL_UPDATE_* options, CMake will automatically regenerate those files and copy any changes back to the source tree. This makes it easier to integrate a source drop with another build system without taking a hard dependency on CMake, although that requires porting the build logic to your own system.
cppgraphqlgen - Use less memory and make parsing/validation much faster

Published by wravery almost 4 years ago

There are many miscellaneous improvements, but the core set of changes are refactoring the way that query validation and introspection work together, and how state is propagated from an object or list to the sub-fields/elements. The GraphQL parser grammar and AST generation are much more efficient and almost entirely avoid memory copies or string comparisons, except in cases where the query actually requires decoding UTF-16 escaped character sequences. The graphql::response::Value type (similar to a JSON value) is much more compact and we defer building them until we're ready to return the final result of a query, so we spend much less time and memory propagating results from sub-fields back to the final result. To support scenarios where services might not want to expose Introspection in production, schemagen now takes a new --no-introspection flag which will suppress the top-level __schema and __type fields. Compared to v3.3.0, the memory usage of the benchmark utility which parses and executes a query 100 times uses roughly 34% as much heap memory at peak, and it runs roughly 38x faster (measured with valgrind tool=massif with GCC on Linux). Many thanks to @barbieri who suggested and/or implemented most of these improvements!

I think this version is source compatible with v3.3.0, except for the definition of service::field_path. If you have any code which propagated or directly manipulated the SelectionSetParams::errorPath parameter, you may get a build break. You should consider that an opaque type and let graphqlservice take care of translating that in the error handling. Take a look at the changes in TodayMock.cpp to see what I mean, I needed to remove some redundant special handling I had implemented there to propagate the paths.

Otherwise, public methods which have been replaced are annotated with [[deprecated]] and include a message letting you know what to move to. They should still work until you are able to update your code. as long as you treat calling deprecated methods as a warning rather than an error. Those methods will be removed in the next major version update, whenever that becomes necessary.

There was a breaking change in PEGTL since the 3.1.0 release which this version of cppgraphqlgen depends on, so for now you need to either recursively clone the repo and update the PEGTL sub-module at the same, or you need to make sure that you're using a commit greater than or equal to https://github.com/taocpp/PEGTL/commit/0cc3128e07734fb72e23e2eeee70b9f1fc13ca5f. If you are using vcpkg, you can install both pegtl and cppgraphqlgen with the --head parameter, otherwise you should stick to the previous release until both the pegtl port and the cppgraphqlgen port have been updated. I will probably do that shortly after PEGTL releases 3.1.1 including that commit.

cppgraphqlgen - NotifySubscribe/NotifyUnsubscribe and Update to PEGTL 3.0.0 Release

Published by wravery almost 4 years ago

I bumped the minor version to 3.3.0 to reflect the new NotifySubscribe/NotifyUnsubscribe feature. The update to PEGTL technically breaks backwards compatibility with older compilers/toolchains, so I could also bump it up to 4.0.0, but since it's still source compatible with prior versions I left it as is.

  • Support for invoking the default Subscription object resolvers on subscribe/unsubscribe.
    • If there's a default Subscription object passed to the Operations constructor, and you call one of the overloads which takes a std::launch policy, it will resolve the subscription query on subscribe with ResolverContext::NotifySubscribe, and on unsubscribe with ResolverContext::NotifyUnsubscribe.
    • Using the older subscribe/unsubscribe overrides, or leaving the default Subscription argument empty, should behave the same as before, except there's now an additional FieldParams::resolverContext member which you may inspect at runtime.
    • You can still override the Subscription object when calling deliver to separate subscription state management from the delivery of events. If you pass deliver a nullptr, it will still fallback to using the default Subscription object.
  • Update the PEGTL submodule to the 3.0.0 release tag which just came out.
    • Remove the boot-filesystem fallback now that PEGTL depends on std::filesystem as well, which bumps the minimum compiler toolchain version up on Linux.
    • Clarify compatibility requirements in the README
  • Other
    • Miscellaneous bug fixes.
    • Enable clang-format and use that to re-format almost everything.
cppgraphqlgen - Make fragment type conditions handle union membership

Published by wravery almost 4 years ago

This is a bugfix release specifically for #112. Unions still work with inline fragment spreads on the option types, but without this fix it's much harder to encapsulate your union handling in standalone fragment definitions.

cppgraphqlgen - Bug fixes and CMake build and versioning improvements

Published by wravery over 4 years ago

Bugs fixed: #105 and #106

You can now build cppgraphqlgen using the add_subdirectory command in CMake as an alternative to importing it with find_package from an external installation.

The version number of the project was getting out of sync with the release tags in git, so now it keeps track of the project version number in a separate version.txt file. Anytime there's a new release tag with a greater version number, the CMake configuration should bump the version it uses in version.txt up to match. This should make it so clones of the git repo automatically stay up to date with released version numbers, and worst case if I forget to bump version.txt before tagging a release, consumers building from a non-git source archive should be at most 1 version number behind since it will have been last updated when building the prior version.

cppgraphqlgen - Update to latest 3.0.0-pre commit from PEGTL

Published by wravery over 4 years ago

Aside from a couple of bug fixes, the biggest difference in this release is that it picked up and fixed a few breaking changes in PEGTL since the last sub-module update. The 3.0.0 version of PEGTL is in a pre-release state and may still introduce breaking changes.

I'm going to submit a PR to update both packages simultaneously in vcpkg. If you use another package manager which doesn't use the sub-module and you want to update cppgraphqlgen to this release, please check whether there's a matching update for PEGTL to go with it.

cppgraphqlgen - Fix VS 2017 compilation plus minor build tweaks

Published by wravery over 4 years ago

The biggest difference between this release and v3.2.0 is a fix for #97, which was a template compilation break in GraphQLService.h specific to VS 2017. I use VS 2019 on Windows which compiled the previous version just fine, and so do gcc and clang on Linux and Mac.

I also updated the optional PEGTL sub-module to the latest master branch commit, and I re-added a GRAPHQL_BUILD_SCHEMAGEN CMake option to suppress building schemagen. I use that in some of my own build pipelines to build schemagen for the host platform and cross-compile the libraries for other target platforms.

cppgraphqlgen - Use explicit DLL exports on Windows

Published by wravery over 4 years ago

This should be backwards compatible at the source/CMake level with previous 3.x versions, but the change is big enough that I decided to rev the minor version to 3.2.

Previously, if you used BUILD_SHARED_LIBS on Windows (including building with vcpkg by default), it was setting CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS and letting CMake figure out all of the symbols in all of the DLLs and mark them as exported. That bloats the import libs which are used to consume them and increases the binary size considerably.

This release replaces that mechanism with explicit __declspec(dllimport/dllimport) attributes defined conditionally through macros on Windows for the methods which are actually referenced across modules. There should be no duplication of symbols between DLLs, and part of that meant I needed to split graphqlresponse into an independent library target/DLL in order to take a dependency on it from both graphqljson and graphqlservice.

I've tested this with static and shared libraries on Windows and Linux, as well as building with vcpkg and verifying that schemagen and the samples/tests still work.

cppgraphqlgen - Doc updates and assorted bug fixes

Published by wravery over 4 years ago

This is a minor update on top of v3.1.0. The only noticeable change at runtime should be that default arguments of scalar String type should be returned properly from Introspection queries.

This is necessary to get GraphiQL working again, now that we include @deprecated(reason: String = "No longer supported") in the schema. It wanted to parse the string in defaultValue as a GraphQL input type, and not having the quotes embedded in the response broke the parser.

cppgraphqlgen - Feature release: Query Validation

Published by wravery over 4 years ago

This is a comprehensive fix for #69. Per the spec, the service ought to validate every query before execution to make sure the results are not ambiguous.

There may still be runtime field errors that this doesn't catch, and since the last time I looked at that section of the spec there also seems to be a lot more guidance about how to format the errors. I added locations to all of the errors I could, and a path to the runtime field errors.

In the process of building the validation feature with TDD based on the Examples and Counter Examples in the spec, I found a few bugs in SchemaGenerator as well and fixed those. The validation relies on Introspection and helped flush those out.

Validation can be performed separately with Request::validate, or you can use the new Request::resolve overloads which take a peg::ast& query parameter instead of a const peg::ast_node& root parameter, they will make sure the query is validated once before executing it. The old Request::resolve overloads are still there for backwards compatibility, but they have been marked as [[deprecated]]. They will go away the next time there's a major version release.

cppgraphqlgen - Fix a few bugs in schemagen and add documentation

Published by wravery about 5 years ago

If v3.0.3 was working for your GraphQL schema already, this update should not change any runtime behavior. It fixes a couple of bugs in schemagen (#72 and #74), and it adds documentation in the doc sub-directory which among other things clarifies how to handle subscriptions (#67).

cppgraphqlgen - Various bug fixes including a crash in schema_exception destructor

Published by wravery about 5 years ago

Most notably, this release should be better at bubbling up schema_exception and preserving error messages from deeper in the query resolution process.

At least on Windows with VS 2019, the copy constructor hiding that I tried for the fix to #63 broke the contract for std::exception and resulted in a crash when the schema_exception was copied but didn't invoke the default copy of the _errors member. That bug has been in there since v3.0.1.

cppgraphqlgen - Work around `std::vector<std::string>` linker issue

Published by wravery about 5 years ago

I changed the semantics of the service::schema_exception constructors a bit in order to work around what seems to be a linker bug. Using type inference compiles OK with the syntax service::schema_exception({ std::string(...) }), but it complains that it can't find the definition of std::vector<std::string> if there are no explicitly constructed instances of that type.

Oddly enough, switching to initializer syntax with an extra {} instead of '()' for the constructor (e.g. service::schema_exception { { std::string(...) } }) seems to be enough of a hint to the compiler/linker to include the necessary pieces of std::vector<std::string>. This should be backwards compatible with code that still uses the old syntax, so not a breaking change, but if you continue using that syntax you might encounter the same linker bug (or whatever subtle C++ behavior this is).

cppgraphqlgen - Update to the latest version of PEGTL

Published by wravery about 5 years ago

I pulled the latest commits from PEGTL and found that the parse_tree::basic_node::is<> method was renamed to parse_tree::basic_node::is_type<>.

cppgraphqlgen - Update to C++17

Published by wravery over 5 years ago

Highlights from #52:

Adopting C++17

  • Move to PEGTL master/3.0.0 (not yet officially released)
  • Use std::variant for response::Value
  • Replace std::unique_ptr for nullable fields with std::optional

Schemagen improvements

  • Make NYI stub generation optional
  • Split the class definitions/declarations into separate files. May also help with making the NYI stubs optional (i.e. decide whether or not to compile and link them individually).
  • Improve error handling/reporting.
  • Add command line options for things like defining a target directory.
  • Change the names of the generated Mutation accessors to something like applyFieldName. Calling everything getFieldName feels strange when performing a mutation.

Miscellaneous

  • Introduce service::FieldResult which handles returning either by value of T or as a std::future<T>
  • Let the caller specify the std::launch policy for the Request::resolve top-level call.
  • Build a separate library target for the grammar/AST.
  • Replace std::string with std::string_view where appropriate.
  • Replace ast<std::string> with ast<std::vector<char>> to deal with small-string-optimization issues rather than reserving extra space when the string is too short.
  • Replace the facebook::graphql namespace with just graphql for the sake of brevity.
cppgraphqlgen - Implement default NYI stubs

Published by wravery over 5 years ago

I was finding it difficult to get started with a new schema or to add types to an existing schema since all of the pure virtual methods would need to be defined on the subclass before it could even link. The new feature in this release is that schemagen will generate stub implementations which throw a std::runtime_error exception and bubble up a "not implemented" message to the field error if they are not overridden.

This release also includes the fix for Issue #44 handling schema extensions and PR #42 which cleans up some of the USE_RAPIDJSON handling in CMake.

cppgraphqlgen - Fix schema extension handling

Published by wravery over 5 years ago

Bug fix release with the fix for #44 in schemagen.

Package Rankings
Top 8.17% on Proxy.golang.org
Related Projects