Session: Object-Oriented Strategies for Custom WPGraphQL Extensions

Date: Thursday, July 30, 2020
Time: 3:00 - 3:45 pm (CDT) (UTC-05:00)
Track: Eduwapuu
Format: General Lecture Session

Who is this session for?

Web Developers of all kinds, Server Administrators

Session description

WPGraphQL is one of the most exciting plugins to come out in recent history. Developers can now build headless WordPress applications with GraphQL rather than use the WordPress REST API. This lets us take advantage of a wide range of modern tools and technologies such as: gatsby js, next (or nuxt) js, Apollo, and more.

But what happens when you need to incorporate other non-GraphQL APIs into your project? Or some of the data you need from your database isn’t covered by WPGraphQL? Do you need to use a combination of GraphQL and REST APIs or SQL queries in your headless application? Not at all! In this presentation, you’ll learn how to use an Object Oriented Programming approach to create maintainable custom WPGraphQL extensions to handle exactly these kinds of cases. The concepts you’ll learn will allow you to:

  • Understand GraphQL, WPGraphQL and their roles in WordPress development
  • Use WPGraphQL with any data source
  • Debug your code!

Presenter

Adam Berkowitz

Headshot of Adam Berkowitz
Web Developer, University of Connecticut

Adam Berkowitz is a web developer for the University of Connecticut’s office of University Communications. In his position there, Adam has taken an active role in the area of web accessibility. Other technical interests of Adam’s include: javascript application development, learning about Docker and containerization, and blogging. A self-taught developer, Adam switched careers from music performance and education to web development in 2016. Outside of work, Adam enjoys spending time with his family.

Sessions

  • General Lecture Session: Object-Oriented Strategies for Custom WPGraphQL Extensions

Session video

Session transcript

Adam (Presenter): Hello, everyone. Thank you for being here today. I am sad to not be in person, but I'm happy to share with you. I'm administrator, I work at University of Connecticut at the Office of University Communications. Before we begin, as Eric said, ask questions on the watch page with the Q & A feature. You can find me on Slack. I will share how I learned to build custom externalness to the WPGraphQL in a robust and maintainable way.

I want to share history and context for the application. You can view the GitRepo with the links on the slide. This helps us find information about doctors in the University of Connecticut health network. Primary care doctors, specialists and dentists can be found in the application.

From a user perspective, you can search by last name, location, or specialty. It routes people to a list of results and they can see attributes of individual providers and fill out a form. It became more difficult to maintain and understand with the original technology.

I decided it was time to rewrite it from scratch with new tech. I decided to view as a front-end framework and decided to use GraphQL and decided to experiment and learn. From a developer perspective, this made its data requests through the browser. It's been divided in two plugins.

One is single page, the other is server-side and manages data with GraphQL. This helps us proxy requests and take advantage of caching strategies. There's a public read only restAPI. I can research and develop each independently. If we needed to replace or change the plugin, we can do so without tearing up the entire project.

I will discuss the server-side plugin and how I used the approach to manage it and an introduction to GraphQL. I want to make sure you understand what GraphQL is and what it's not.

We'll start what it's not. It's not the same as REST. WordPress has a REST API that many are familiar with, with endpoints, pages, posts, authors, etc. Personally, I don't know what data comes back. For example, I can't tell you what data comes back with a request for posts. I can look at documentation and guess, but it's just a guess.

I bet I could figure out the title, content, link and slugger part of the data, but after that, I had no idea.

It turns out, this is the data coming back from the post in the request. Not only that, but all data comes back whether we want it or not. What if we want a few things for a blog index? Do we need the ping and dig into meta data for the name? This describes resources, true for every REST API, not just this API. REST endpoints match up with data in the database.

REST API doesn't make an assumption for what data you want, but all of it. WPGraphQL is a query language, similar to SQL. With SQL, we have a model for specific information and only that information from a database. It's in part because it's a query language, tools and languages to maintain data. We can get specific information from database or API. You start from the bottom and read towards the top, it reads like a WPGraphQL query, like this.

This may look different but the purpose is the same. You get specific data and only that data for published posts. This can be helpful for a variety of reasons. One of the most important is that I know exactly what data to expect from the application and documented in the request itself and graphical application or GraphQL playground. We limit the size of the request across the network.

All requests are made to GraphQL endpoint and make associations between data types. WPGraphQL makes it easy to make this available when building projects. It does so well and is integrated into Gatsby's WordPress plugin. Unfortunately, there are hooks and methods that allows us to build extensions with WPGraphQL. Some turn this into plugins like the Advanced Custom fields plugin. We needed another API.

In order to do that, I needed to understand what parts of the GraphQL request. All GraphQL requests start with a query for data or a mutation. All aspects will apply to the terms. Reading data is a query. Everything else is as mutation.

After this point, I was confused. The terminology was getting in the way of progress. I had a hard time with what the terms represented and implemented. You may say, "You need to read the documentation." I had done that and it practically hadn't helped me. I had incentive to figure it out due to production.

As I built my plugin, I used my confusion and the structure to help me. By breaking the vocabulary word into a directory, I focused my attention carefully. No mutations made it to production, and all other GraphQL were queries and I didn't need the rest.

This made sure no single file was too large to understand. This is all very nice. I still needed a way to ensure stability across the project.

I needed to find a way to mimic the rigor of GraphQL. It's very strongly typed. It ALWAYS enforces a contract between server, GraphQL implementation and request. Every implementation throws errors if you don't conform to expectations.

In honesty, that's good, depending on how the errors are described. As I thought about what I wanted, I reflected on the presentation on Object-Oriented WordPress Development that Dash gave last year. Their presentation was helpful because I considered new approaches I hadn't tried before. I learned by trying Larabel and get a handle on that framework and organization.

By thinking about how I use Object-Oriented programming and PHP features, I made good progress and met my goals. I'll focus on GraphQL types. I'll touch on the other parts after that.

You'll see the overall pattern will repeat. You can use GraphQL with a wide variety of data. Until you tell the client/server the properties, you won't get very far. These data will to represented by object or PHP associated array with properties. My data to represent included doctors. They had a wide variety of attributes, names, IDs, doctor's education, etc.

Some are more complex and needed to be connected with provider type. With these ideas, I built Object-Oriented integration with WPGraphQL. Every directory is separate part of the name space of the project. That way, I can keep code organized and narrow down errors and I build and debug. WPGraphQL will tell you what is outside the namespace.

Every file in directory is added to namespace and folder structure. I can keep track easily and avoiding naming collisions. I wanted an enforceable structure for each class. Each type I create needs certain methods, primarily a way to get configuration of the type, for instance, a name represented by string, and then register a type. You may need a different kind of object type. I looked at the types I needed to represent and they were similar.

Using interface like this wasn't necessary, but an extension of the goals. It would keep me honest in building the class and helping me stay dry. Any class must use these methods. If they return something, they follow the type defined in the interface for the return value. In the case of the git config, they must return an array or PHP will return an error. The implementation for the method is up to the class. They have to exist. Let's see what that looks like.

To expand the interface, I made parent function type classes. Custom type class uses methods from interface. I wanted each type separately; git config returns an empty array and satisfies interface requirement.

Register type method is the WPGraphQL restored WPGraphQL type function as a closer. This will register the type. There are two arguments, the type's name and configuration as array. Both are in the class.

I create new instance of class with type name in constructor. It doesn't do anything without the register type method, but doesn't break either. So far, so stable.

Every class inherits the custom type class has the methods and keep the implementation for the child's classes are dry. There's no need for registered type method without a reason. They focus on configuration methods, and don't need to be concerned with anything else.

This is what it looks like. [Showing.] This is the sketch of the type to define properties of doctor/dentist. This returns the information with WPGraphQL. There's description and fields. The subarray tells the server what information is available for requests.

If it's not defined in the information, it's not available with GraphQL though it is with the outside API. This is useful with specific data and specific requirements. These cases can be managed by looking at the environment and modifying according.

Configuration array is documentation displayed in GraphQL playground. This is a closer look. Every aspect is defined. GraphQL is strongly typed and you defined a property in advance.

For instance, you can make fields non-null or required. You can define as a list. You may need a list of strings for names. GraphQL defines basic types, strings, integers, and bullions. You can associate types between each other. This is what I defined and connected elsewhere in the app. I had close to 20 and needed to bring them in a register. First, I'll show the bad way. Second, I'll show you the better ways for future projects and an update.

Every type needs a separate function that I create. Inside, I create a class instance and call register type method. This works because WordPress can handle calling public class method as part of an action.

Ultimately, this helps me keep plugin.php small. After doing administrative checks, this is three lines long, one each for type register, fields and connections register.

When I create a new type register, every method is called when the GraphQL register type action is run.

It's good for plugin.PHP file, it's a bad way to manage the class. One, it's not very dry. I have to type up "you" statements, function names, etc.

If I needed to add functionality to the class, it's hard. Either I can't, or modify the array filter. All in all, not my best work. At the time, I was focused on the GraphQL part, not the PHP part, so it didn't bother me, until it did. A few weeks ago, this approach felt terrible when thinking about the presentation and decided to change it. First, I learned you can resolve closes from strings by resolving it to a variable. The actual class name is stored as variable, with the name.

From there, create new instance of the class and store that as a variable, too. With that in mind, create a data file, with arrays and class names for the same result. Use any array methods to interact with the data.

You can iterate over it to modify, filter, and manage it. This led to a different and better approach for registering classes. You can see the boiler plate extension plugin at the link in the bottom right corner.

Now I have a data file and it can be read and included in the type register class. Dash helped me recursion to traverse the data file in other methods, here. This lets me manage the class as variables. Each variable is a full class name and I create an instance and store in a resolved variable. With name call back, you can't use additional arguments that aren't passed by WordPress plugin.

An anonymous function is useful. PHP use keyword, you have arguments that aren't part of the original set and patches the resolved class and the closure. This reduces the methods written for the class to work correctly. I can write other methods and call them separately without filtering them out.

In the context of typed classes, keep in mind that a registered type method was registered for each one. This was enforced by this interface before and wasn't an issue. I like the PHP methods like arrays and the array map. This allows me to return an array as the available method as a check. This ensure I can check the original array without confusion on its modification.

At this point, the project directories look like the ones for the types directory. There's a file with a custom type parent case, and extended with child files. They are collected in a type register. It can be created and managed in my Custom.PHP file. I can customize it in a similar way. The fields, connections, and resolver directories all look like this, too. I won't belabor the strategy. But I want to talk about GraphQL and what it looks like and the methods to use.

I created lists for you to look through at your convenience. If you have types and register with WPGraphQL and look at the GraphQL playground, you'll be disappointed. There's nothing in the documentation and only show up when you register a field with GraphQL function. A field is a single association to a query and resolves a single type. For example, a query asking for one provider. You could use a query filter for each field, used in the gist. These are either the database or profile ID.

Often, we need data in a collection. To make that happen, we need a GraphQL connection, that includes multiple associations to a query and plural types. For instance, a query that asks for many providers. You create arguments to filter the data.

Like SQL filters, they use the keyword "where." You see "edges" or "nodes" in GraphQL. These are conventions to represent collections of data. In this case, each node is a single provider.

This is a good time to review what we know. We have a query or mutation, a GIT or post HTTP request. We then go to types, fields/connections. The last is the resolver that functions to return the data. You'll see how I implemented them in WordPress and GraphQL in an Object-Oriented way.

This is the last part of the sequence, the resolver. This is how we manage the information that comes back from API and sent data. Resolvers are the hardest thing for me to understand. You may not think so since it's a fancy way to say a function, but there you have it. As a musician, I thought of chord resolutions, but that didn't help.

A query/mutation is tension, work that needs to be done. Resolvers manage the tension and filter/manipulate the request until the resolution is reached, which is represented by the returned data. I understood that and realized I needed singular or plural methods of data. That's how I came up with the project.

I decided to be obvious and call it single node resolver and multiple nodes resolver. Single node resolver was used for resolving fields and multiple nodes was used for resolving connections. If you're following on, look at the gist I made to demonstrate these more fully. It explains the argument for the function and what they do.

I have abbreviated some of the method. It should give you an idea of how a resolver works. You can use the arguments to flow, check and create and filter. You can flesh, cache and return data. Anything outside of GraphQL happens here.

In this case, I wanted to demonstrate how I might query doctors by last name. First, I created the last name argument. Then I use the SDK that Brian Keller wrote, making caching available. I used the last name argument, used as a promoter when API is called. Following GraphQL convention, I return these as a property of the key nodes.

Much like types, fields and connections require configuration arrays with the GraphQL plugin. One key is tied to the resolver function, where we create a new resolver class and use methods from it.

Of course, things never go this smoothly in development. The WPGraphQL documentation does a nice job of explaining good techniques for debugging the GraphQL responses.

These connection mistakes are easy to make and involve putting properties in the wrong arrays. None of the techniques worked. I fell back on something to rely on, HTTP requests. You can copy/paste queries into an app, Postman and involve the var_dump in the resolver, appearing before the query. The only way to understand what is happening is understand the request as it was happening.

For instance, when I had something taking too long with WordPress and didn't handle the error well . . . At this point, why bother with any of this? Can't I make a Git request to RESTAPI and skip WPGraphQL and object orientation? That's a good side. There are some downslides to GraphQL.

The most obvious, I maintain an extra plugin. You don't have to, but it's a way to focus my effort and a model/view/controller approach. We have some debt. We need other PHP GraphQL implementation. PHP GraphQL is solid. In that time, the debt was incurred.

There are definite upsides. One of the obvious, creating associations between data structures not normally available. There's no rest endpoint for the doctors working a particular clinic. We could make that in GraphQL and get a list of doctors based on cached results.

Another upside, the ability to build a variety of applicants in the model. Like Jam site with Gatsby. Or a plugin that works in a larger WordPress environment, like the one running in the health network. I need both requests for the same GraphQL. Those are both choices within the model.

As a developer, I wanted to highlight the ease of which you can request through the server or the browser. I found difficulties with Apollo, but it was great overall, and made the JavaScript much easier. It's easier to make requests from server to browser. You add one keyword. The GraphQL has the atclient decorator for queries and mutations. You use this and Apollo understands it should be made through browser and not server.

I made this gist to demonstrate this. The data returned by GraphQL will be the same. Not only that, if we need a list of providers, we create the association here through Apollo, though it doesn't exist in the current API.

As we wrap up, I wanted to make sure you have resources available and hopefully you will find these helpful. To sum up, WPGraphQL is an amazing program you should check out. By using API as a start and taking an Object-Oriented approach, I could clearly understand and debug a plugin without something I didn't have a lot of experience in. I am excited to learn more about this in the feature.

Please reach out via email or twitter. I am happy to work with people and extend the ideas and work on projects. I would like to thank everyone here at WPCampus who helped put this together. Thank you for letting me present.

Eric (Room Host ): Alright, Adam. It's safe to assume you collectively have blown our minds with your knowledge and expertise. As we receiver from being dazed, I want to thank you for your breakdown of an intense subject. I appreciate it and I know our audience does, too.

Adam: Thanks for helping with our rooms for the last few days. It's been amazing.

Login to WordPress