This blog post is about will give you complete knowledge about how to start with react Graphql using typescript and the separation of concern and clean architecture folder structure.
Keep in mind that if you get stuck on any step, refer to the Github repo
To find the completed project, Demo link
This is what we are going to create:
What is GraphQL?
Before going forward, let me give a very brief overview of GraphQL and what all things we are going to discuss. So GraphQL is a query language for APIs that is developed by Facebook. It is an efficient alternative to REST because of its features such as:
- With GraphQL there's no over fetching or under fetching of data, unlike REST.
- Strongly typed graphQL schema which can be written in GraphQL Schema Definition Language (SDL) helps you validate your API requests during its compile time.
- With the development of various GraphQL libraries (Apollo, Relay, etc) you are getting a lot of features such as caching, realtime data, etc.
- It provides a large and amazing community! You can always get your queries answered whenever stuck.
This was just a basic introduction to GraphQL, but I recommend you to visit the site to gain deeper insights of the same.
What we'll do?
I will be mainly focussing on the front-end side, where I am gonna explain the two very useful react hooks useQuery and useMutation, how are we using these in our project for GraphQL operations along with the code.
Wait...what are GraphQL operations?
GraphQL provides various types of operations such as Query, Mutation, and Subscription which act as the entry points for the requests sent by the client. In this blog, I'll be discussing the first two types i.e. Query and Mutation.
I'm going to use graphql-hooks have two operations useQuery, useMutation
UseQuery: Basic syntax:
const { loading, error, data } = useQuery<Type1, Type2>(
QUERY_STRING,
{ variables: <variable>,
onCompleted:()=>{console.log("query successful",data);}
,
onError:(error)=>{console.error(error);},
});
data : The required data we are getting after the query is successful.
loading : It is a boolean value, if true, it means the query is still in flight. After it is successful the value of loading changes to false.
error : It stores the error if occurred while querying.
useMutation: Basic syntax:
const [mutateFunction,{ error,loading}] = useMutation<Type>(MUTATION_STRING, {
onCompleted: () => {
console.log("details updated")
},
onError: (error) => {
onError:(error)=>console.error(error);
},
refetchQueries: [{ query: QUERY_STRING, variables: <variable>],
});
mutateFunction : It is the mutate function which can be called anytime to run the mutation.
The second parameter is the object representing the mutation's execution status such as error , loading which have been explained above.
To use those operation in App need to wrap your app with the provider:
import { GraphQLClient, ClientContext } from 'graphql-hooks'
const client = new GraphQLClient({
url: '/graphql'
})
function App() {
return (
<ClientContext.Provider value={client}>
{/* children */}
</ClientContext.Provider>
)
}
Now in your child components you can make use of useQuery
import { useQuery } from 'graphql-hooks'
const HOMEPAGE_QUERY = `query HomePage($limit: Int) {
users(limit: $limit) {
id
name
}
}`
function MyComponent() {
const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {
variables: {
limit: 10
}
})
if (loading) return 'Loading...'
if (error) return 'Something Bad Happened'
return (
<ul>
{data.users.map(({ id, name }) => (
<li key={id}>{name}</li>
))}
</ul>
)
}
More details and options you can refer link
Our project's structure:
Before we begin let's talk about how our project is going to be organized.
Once we create our React app using create-react-app, we will have our base React app. Once inside that application, we will create a component pattern and Our folder structure will look like the following:
Now, let’s go over the folders one by one and the and understand the motivation behind them and the type of files you would store in them:
src/ - Contains all of our react codebase.
graphql - queries: This folder contains all static graphql query with props settings
pages - The name is pretty self-explanatory. It contains all the Stateful Components as discussed above.
views - This folder contains all the Presentational/Stateless Components as discussed above.
routes - This folder contains public, private, session differentiation and mainly for App navigation
start - Base react component.
types - Typescript related files or functions.
utils - Helper functions
use - custom hooks
templates - I create a different template for React with React Router 4 like global, error handling, promotions like so on.
Hopefully you understood how to setup a clean, efficient and maintainable folder structure for your React Apps.
Our goal today is to:
- Create a new React Blogger App
- Have Graphqlzero almansi Api
- Using React Routing, be able to navigate our app
Generate project with CreateReactApp:
I often (to not say always 😁) use Create React App to initiate my React projects.
In order to generate our project run :
npx create-react-app my-app --template typescript
let's start coding.
Setting up React Router:
To get React Router going, we are going to need to install our dependency. In the project, run the following command:
npm install --save react-router-dom
It define the route and call the Auth.
// src/start/Routes.tsx
routesTemplates.map((routesTemplate) => {
const { routes: appRoutes, template: Template , type} = routesTemplate;
return appRoutes.map( (appRoute) => {
return (
<Route
exact={appRoute.exact}
path={appRoute.path}
key={appRoute.path}
render={(route) =>
<Auth
appRoute={appRoute}
Template={Template}
route={route}
type={type}
/>
}
/>
);
});
})
Route Types
There are three route types defined in the project.
// src/routes/routeTypes.tsx
export enum routeTypes {
private = 'private',
public = 'public',
session= 'session',
}
private: private pages like profile, edit-profile, etc. If the user isn’t logged then must to show the login page.
public: public pages like about-us, contact, etc.
session: session pages like login and sign-up. If the user is logged then must to redirect to the private dashboard.
Routes Template
In this file you can define the routes, the template and the rights (public, private, session).
// src/routes/index.tsx
const routesTemplate: IRouteTemplate[] = [
{
routes: privateRoutes,
template: GlobalLayout,
type: routeTypes.private,
},
...
];
Auth
Verify the rights and redirection.
// src/start/Auth.tsx
if (isPrivate(type) && !global.logged) {
return <GlobalLayout Component={Error403} route={route} />;
}
if (isSession(type) && global.logged) {
return <Redirect to="/" />
}
const Layout = appRoute.template ? appRoute.template : Template;
return <Layout
Component={appRoute.component}
route={route}
/>;
Building our React components
In this application, we are going to have fives pages for templates:
- All Posts List with Author Details
- All Author List with Posts listing
- Post details
Putting it all together
Now that we have our components set up, we can head on over to “localhost:3000” and see all pages get render.
Feel free to ask questions in any area you don't understand.
To be continued on next article about Graphql implementation...
Top comments (2)
Great post. Thank you Selva.
Couldn't access the github repo. Could you share the correct link?
Decent post!
I would suggest formatting your code blocks, spotted some inconsistencies ) ✍