GraphQL Delivery on Golang’s Clean Architecture
Implement GraphQL on Golang Clean Architecture
Clean architecture, is one of the popular architecture in programming. It’s known for its good separation concern between each layer. Each layer doesn’t need to know about the other layer implementation, so we can easily change the implementation without making changes on the other layer. If you want to know more about clean architecture, you can read it here because I won’t tell detailed explanation about it in this post.
Today, I want to try implementing GraphQL in my friend code about clean architecture in Golang, you can read his awesome post here “Trying Clean Architecture on Golang”. On that post, the writer uses REST API as the delivery layer, now I will try to add more HTTP layer which is using GraphQL.
What is GraphQL? By the definition from their website:
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
In other’s word, GraphQL is a query language for Client to get only what they ask, without receiving unused data. So if we have an article object like this one:
"title": "Indonesia won the award of best clean air of South East Asia",
And the Client only wants the
title field, the server will only return:
"title": "Indonesia won the award of best clean air of South East Asia"
To start using GraphQL, we need to define our schema based on our
Usecase layer. So based on this github, we have article struct:
We can make Article type on our GraphQL Schema like this one:
On GraphQL, it has 5 default scalar type, there are:
With that, we can map our Golang
int64 datatype to
Int scalar types on GraphQL. For the
Time type on Golang, GraphQL support creating a custom scalar types, so we need to define
Time scalar types in the schema we wrote.
After creating the object type, we need to create
Mutation for the GraphQL schema. These 2 types will be created based on
Usecase interface of the clean architecture code here is the code of the
What is the difference between
Mutation in GraphQL? For short
Query is used to retrieve data, and
Mutation is used to modify or create data on the server. So based on the
usecaseinterface, we can write Query and Mutation like this one:
You must be asking,
Wait, what is ArticlesResult on FetchArticle line? There is no ArticlesResult type in the type schema before! Why not just returning list of articles instead?
FetchArticle function, we need pagination and cursoring feature so we will not get all the articles by one request. In GraphQL, there is a standard type for implementing pagination, based on this page we need to create a connection (edge) and the info (pageInfo) of the current object, and that’s why we need to create
ArticlesResult object. Here’s the schema type for the
Edge type will have
String type and
Article type. cursor is the connection value for the current article with its neighborhood article. We can get the next article with this
PageInfo type will have
String type and
endCursor is the value of the last cursor of the current edges, so we can get the next edges with this value.
hasNextPage will be our flag whether this list of edge has next page or not.
ArticlesResult type will have
edges type with an array of
PageInfo type, and
totalCount will have the value of total items of the current edges.
All of the GraphQL type (object, mutation, and schema) can be written in the same file, so here is the
Dive into GraphQL Go
After the schema already defined, we need to transform it into Golang’s code. For this tutorial, we will use graphql package. I choose to use this package because of its modularity, so we can use it with our clean code architecture.
Transforming object type schema
Firstly, we need to make GraphQL object based on our schema, here is the code:
To be able to utilize the package function of a resolver, we need to create a function which implements the
FieldResolveFn . We can just create a function for each resolver, but this time we will make an interface which has all the
Mutation function from the schema, so it can be initiated with article service layer injected (and easier testing).
Creating Schema Constructor
We will need to create GraphQL object with all of the type explicitly written. What I mean is we have to create object for
StoreArticle , and
DeleteArticle declared. The previous resolver will be injected in the GraphQL object schema to be able to use its method. Here is the code:
Don’t forget to write the implementation of the
Resolver interface. We will create an internal struct which implements all the required method of the interface and also injected with the article service layer so we can access the article data.
Why don’t we just directly inject the article repository layer? It is because we treat resolver as another delivery layer, the delivery layer cannot directly access the repository layer, so we need to utilize the service layer.
I think it will be a good practice to write the other implementation by yourself, so you can explore what other options the package has. But overall, the code will be written like this:
Initializing the GraphQL Delivery
And for the final step, we need to initialize our GraphQL delivery on the
main.go file. Just modify the file like this one:
We use https://github.com/graphql-go/handler package to create a GraphQL HTTP handler and pass the handler into
echo WrapHandler function, but if you don’t want to use it, you can create your own Handler by following the rules from https://graphql.org/learn/serving-over-http/.
Now our go-clean-arch already have another delivery layer which uses GraphQL, just run your application and access it from
/graphql path. We will also have GraphiQL user interface to try the query of GraphQL.
Hope this tutorial helps you to understand about GraphQL and the usefulness of Clean Architecture in Golang.
You can see the full code from my Github here:
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…
Have a great day 🖖🏼!