I’m Mário Mabande
a
Software Engineer
MSc in Computer Science
ML Enthusiast
I design and develop software solutions, from modern web applications to enterprise systems and API integrations. My work combines software engineering, research, and a commitment to building reliable, accessible, and meaningful technology.
My Expertise
App Development & Maintenance
I build reliable, scalable applications for web and mobile — using modern frameworks and proven best practices. Every solution is fast, user-friendly, and easy to maintain, with security built in from the ground up.
Website Design & Optimization
I create fast, responsive websites that turn visitors into customers. Each site is optimized for Core Web Vitals and SEO, delivering standout performance and a seamless experience on every device.
Digital Marketing & SEO
I grow your online presence through smart SEO and targeted ad campaigns across Google, Meta, and beyond — driving more traffic, stronger engagement, and qualified leads that translate into real results.
Featured Projects
Created the official website for Gungu, a Mozambican cultural and media platform that integrates theatre, cinema, television, digital journalism, and streaming services. The website presents Gungu Teatro, Gungu Cinemas, Gungu Televisão, Jornal Dica, and GunguFlix, serving as a centralized digital hub for artistic, audiovisual, and informational content. The project emphasizes cultural valorization, accessibility, and digital innovation, positioning Gungu as a multidisciplinary reference in Mozambique’s creative and media industry. Built with WordPress.
- Link:https://gungu.co.mz/
- Year Created: 2025
- Tools Used: WordPress, Elementor, Contact Form 7, All in One SEO and others.
Malesta ERP (In Development)
Malesta ERP is a modular and scalable ERP platform designed for small and medium enterprises (SMEs) in Mozambique, built on the open-source Odoo Community platform. The system is tailored to local business requirements, ensuring fiscal compliance, and provides pre-configured industry-specific packages for fast and cost-effective deployment.
The platform will feature specialized modules and packages:
- Retail Package – Sales & Point of Sale (PoS) management, inventory and stock control, and simplified financial and sales reporting.
- Office Services Package – Human Resources (HR) management, invoicing and accounting, Customer Relationship Management (CRM) to track client interactions and business opportunities.
- Restaurant Package – PoS management tailored for restaurants, stock control for ingredients and products, and digital menu integration for enhanced customer experience.
Core Functionalities (Planned):
- Centralized Management – integrate all critical business operations into a single platform.
- Automated Compliance – ensure fiscal compliance for invoicing, reporting, and legal requirements.
- Customizable Workflows – adaptable processes for different business types.
- User Training & Support – initial onboarding and ongoing support to optimize operations.
Technologies: Odoo Community, Python, PostgreSQL, JavaScript and others.
Impact (Expected): Streamline SME operations, enhance efficiency, ensure legal compliance, and provide actionable insights to support growth.
WebNews — WordPress Theme
WebNews Premium Theme is a responsive and feature-rich WordPress theme suitable for blogs, news sites, and magazines. It offers multiple homepage layouts, integration with a custom plugin (M3Toolbox), and attention to usability and responsive design.
- Link: https://github.com/mariomthree/webnews-premium-theme-wp
- Technologies: WordPress, PHP, CSS, JavaScript, jQuery
- Impact: First professional WordPress project, demonstrating front-end and PHP skills.



WIM Corporate Website
Created the website for WIM (WIM Industrial Maintenance Welding & Service, LDA), a Mozambican company offering TIG and MIG/MAG welding, industrial maintenance, and supply of electrical and electronic equipment. The site emphasizes WIM’s excellence, customer focus, and innovation, positioning the company as a strategic partner for high-performance industrial solutions. Built with WordPress.
- Link: https://wim.co.mz/
- Year Created: 2023
- Tools Used: WordPress, Elementor, Contact Form 7, Yoast SEO and others.
SysStock
SysStock is an inventory and sales management system for small to medium businesses. It allows product and supplier management, sales tracking, quotations, and report generation with a user-friendly desktop interface.
Technologies: Java (Swing), SQL
Impact: Streamlined inventory and sales management processes, increasing operational efficiency.
SHIGOM Website
Developed the website for SHIGOM, a Mozambican event management company known for professionalism and efficiency. The site showcases weddings, birthdays, conferences, and their elegant venue. It also features past events, client testimonials, and contact information, highlighting the company’s commitment to quality and personalized service. Built with WordPress.
- Link: https://shigom.co.mz/
- Year Created: 2021
- Tools Used: WordPress, Spectra, WPForms, Microthemer and others.
Clients I've Worked With
Engineering Notes
Building a GraphQL API with Python: A Practical Tutorial
Hello, dear readers! 👋
Do you remember our task management API from the article Building a RESTful API with Python? Well, today we are going to rebuild it — but this time speaking a completely different language: GraphQL.
And yes, we will be using Python, our programming language friend, together with Django and a library called Graphene.
In the recent article GraphQL vs REST: When to Choose Each, we covered all the theory: why Facebook created GraphQL, the over-fetching problem, the famous single endpoint. Now it is time to get our hands dirty and see all of that working on our own machine.
By the end of this tutorial, you will have a working GraphQL API with Python where the client asks for exactly the data it wants — and you will be able to compare it, file by file, with the REST version we built before. Same project, two philosophies. Sounds fun? Let’s go! 🚀
Index
- What We Are Building
- Setting Up the Environment
- Creating the Task Model
- The Heart of GraphQL: The Schema
- One Endpoint to Rule Them All
- Playing with GraphiQL
- Testing Our API (Like Professionals)
- REST vs GraphQL: Same Project, Side by Side
- Conclusion
- References
1. What We Are Building
Our old friend: a Task Management API. Each task has a title, a description, and a status that can be PENDING, IN_PROGRESS, or DONE.
But here is the twist. In the REST version, we needed serializers, views, and routers spread across multiple files, plus one URL per resource. In the GraphQL version, we will have:
- One single endpoint:
/graphql/ - One schema file where everything lives
- Queries to read tasks (with the client choosing the fields!)
- Mutations to create, update, and delete tasks
- A free interactive playground called GraphiQL
2. Setting Up the Environment
As always, let’s keep things organized with a virtual environment. Open your terminal and type:
mkdir taskmanager_graphql && cd taskmanager_graphql
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Now, let’s install our ingredients:
pip install django graphene-django
Graphene-Django is the bridge between Django and GraphQL. It knows how to transform our Django models into GraphQL types almost magically — you will see.
Create the project and the app:
django-admin startproject taskmanager_graphql .
python manage.py startapp tasks
Then register both in taskmanager_graphql/settings.py:
INSTALLED_APPS = [
# ... default Django apps ...
'django.contrib.staticfiles',
'graphene_django', # our new friend
'tasks', # our app
]
# Tell Graphene where our schema will live (we will create it soon)
GRAPHENE = {
"SCHEMA": "tasks.schema.schema",
}
3. Creating the Task Model
Open tasks/models.py. If you followed the REST tutorial, this will look very familiar — and that is exactly the point. Same model, so we can compare both worlds fairly:
from django.db import models
class Task(models.Model):
"""Task model — same structure as our REST tutorial,
so you can compare both approaches directly."""
class Status(models.TextChoices):
PENDING = "PENDING", "Pending"
IN_PROGRESS = "IN_PROGRESS", "In Progress"
DONE = "DONE", "Done"
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
status = models.CharField(
max_length=20,
choices=Status.choices,
default=Status.PENDING,
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.title
Run the migrations:
python manage.py makemigrations tasks
python manage.py migrate
Our database is ready. Now comes the interesting part.
4. The Heart of GraphQL: The Schema
Here is where GraphQL really differs from REST. Remember that in the REST tutorial we created serializers.py, then views.py, then registered routes? In GraphQL, all of that lives in one file: the schema.
Create tasks/schema.py. I will build it piece by piece, and for each piece I will tell you its REST “cousin”, so nothing feels alien.
4.1 The Type (cousin of the Serializer)
import graphene
from graphene_django import DjangoObjectType
from .models import Task
class TaskType(DjangoObjectType):
class Meta:
model = Task
fields = ("id", "title", "description", "status", "created_at", "updated_at")
That’s it. DjangoObjectType looks at our model and generates the GraphQL type automatically. In the REST version, our serializer did a similar job — but here we get a strongly typed contract for free.
4.2 Queries (cousins of the list/retrieve views)
class Query(graphene.ObjectType):
all_tasks = graphene.List(
TaskType,
status=graphene.String(required=False),
description="Retrieve all tasks, optionally filtered by status.",
)
task_by_id = graphene.Field(
TaskType,
id=graphene.ID(required=True),
description="Retrieve a single task by its ID.",
)
def resolve_all_tasks(root, info, status=None):
queryset = Task.objects.all()
if status:
queryset = queryset.filter(status=status.upper())
return queryset
def resolve_task_by_id(root, info, id):
try:
return Task.objects.get(pk=id)
except Task.DoesNotExist:
return None
Each field has a resolver — a function that knows how to fetch that data. Notice the small kindness to our users: status.upper() means they can write “pending” or “PENDING”, and both work. Small details make friendly APIs.
4.3 Mutations (cousins of create/update/destroy)
class CreateTask(graphene.Mutation):
class Arguments:
title = graphene.String(required=True)
description = graphene.String(required=False)
task = graphene.Field(TaskType)
ok = graphene.Boolean()
def mutate(root, info, title, description=""):
task = Task.objects.create(title=title, description=description)
return CreateTask(task=task, ok=True)
class UpdateTaskStatus(graphene.Mutation):
class Arguments:
id = graphene.ID(required=True)
status = graphene.String(required=True)
task = graphene.Field(TaskType)
ok = graphene.Boolean()
message = graphene.String()
def mutate(root, info, id, status):
status = status.upper()
valid = [choice[0] for choice in Task.Status.choices]
if status not in valid:
return UpdateTaskStatus(
task=None, ok=False,
message=f"Invalid status. Valid options: {', '.join(valid)}",
)
try:
task = Task.objects.get(pk=id)
except Task.DoesNotExist:
return UpdateTaskStatus(task=None, ok=False, message="Task not found.")
task.status = status
task.save()
return UpdateTaskStatus(task=task, ok=True, message="Status updated.")
class DeleteTask(graphene.Mutation):
class Arguments:
id = graphene.ID(required=True)
ok = graphene.Boolean()
message = graphene.String()
def mutate(root, info, id):
deleted, _ = Task.objects.filter(pk=id).delete()
if deleted:
return DeleteTask(ok=True, message="Task deleted.")
return DeleteTask(ok=False, message="Task not found.")
class Mutation(graphene.ObjectType):
create_task = CreateTask.Field()
update_task_status = UpdateTaskStatus.Field()
delete_task = DeleteTask.Field()
Notice the pattern ok + message in our mutations. Instead of throwing scary errors, our API answers politely: “Invalid status. Valid options: PENDING, IN_PROGRESS, DONE”. Your future front-end colleagues will thank you for this. Trust me.
4.4 The Schema (gluing everything together)
At the end of the file:
schema = graphene.Schema(query=Query, mutation=Mutation)
Four concepts: Type → Query → Mutation → Schema. That is the whole GraphQL mental model.
5. One Endpoint to Rule Them All
In the REST tutorial, we registered several routes. Today, open taskmanager_graphql/urls.py and behold:
from django.contrib import admin
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
urlpatterns = [
path("admin/", admin.site.urls),
# ONE single endpoint — this is GraphQL's philosophy in practice
path("graphql/", csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
One route. That’s all. Everything — reads, writes, deletes — goes through /graphql/. Remember the theory article? This is that “single endpoint” idea, now living in your urls.py.
The graphiql=True parameter gives us a free interactive playground. Let’s meet it.
⚠️ Heads-up:
csrf_exemptandgraphiql=Trueare here to keep the tutorial simple. In production, add authentication, handle CSRF properly, and turn GraphiQL off (or restrict it).
6. Playing with GraphiQL
Start the server:
python manage.py runserver
Now open http://127.0.0.1:8000/graphql/ in your browser and say hello to GraphiQL — an interactive editor with auto-completion and documentation, generated automatically from our schema.

6.1 Creating our first task
Paste this in the left panel and press the play button:
mutation {
createTask(title: "Learn GraphQL", description: "Following the mariomthree tutorial") {
ok
task {
id
title
status
}
}
}

The response confirms: our task was born with status PENDING. Create two or three more — we will need them.
6.2 The magic moment: asking only for what we need
Now, the query that justifies this whole tutorial:
query {
allTasks {
title
status
}
}
Look carefully at the response. Where is the description? Where is createdAt? They are not there — because we did not ask for them.

This is the over-fetching problem from our theory article, solved in front of your eyes. In the REST version, GET /api/tasks/ always returned every field of every task. Here, the client is in control. Try adding id to the query and watch the response change instantly.
6.3 Updating and filtering
Change a task status:
mutation {
updateTaskStatus(id: 1, status: "in_progress") {
ok
message
task { title status }
}
}
And now try to break it (breaking things is how we learn 😄):
mutation {
updateTaskStatus(id: 1, status: "flying") {
ok
message
}
}

Our API answers with ok: false and a helpful message listing the valid options. This is the ok + message pattern earning its keep.
Finally, filter tasks by status:
query {
allTasks(status: "pending") {
title
status
}
}
7. Testing Our API (Like Professionals)
A tutorial that ends without tests is only half a tutorial. Create tasks/tests.py:
import json
from django.test import TestCase, Client
from .models import Task
class GraphQLTaskAPITest(TestCase):
def setUp(self):
self.client = Client()
self.task = Task.objects.create(title="Test task", description="A test")
def query(self, q):
response = self.client.post(
"/graphql/", data=json.dumps({"query": q}),
content_type="application/json",
)
return json.loads(response.content)
def test_query_all_tasks(self):
data = self.query("{ allTasks { title status } }")
self.assertEqual(data["data"]["allTasks"][0]["title"], "Test task")
def test_create_task_mutation(self):
data = self.query('''
mutation { createTask(title: "New task") { ok task { title } } }
''')
self.assertTrue(data["data"]["createTask"]["ok"])
self.assertEqual(Task.objects.count(), 2)
def test_invalid_status_returns_error_message(self):
data = self.query(f'''
mutation {{ updateTaskStatus(id: {self.task.id}, status: "flying") {{ ok message }} }}
''')
self.assertFalse(data["data"]["updateTaskStatus"]["ok"])
self.assertIn("Invalid status", data["data"]["updateTaskStatus"]["message"])
def test_client_chooses_fields(self):
"""The core GraphQL promise: response contains ONLY requested fields."""
data = self.query("{ allTasks { title } }")
task = data["data"]["allTasks"][0]
self.assertIn("title", task)
self.assertNotIn("description", task)
My favorite is the last one: test_client_chooses_fields. It literally proves, in code, the promise that brought us here. Run everything:
python manage.py test

All green. Beautiful. ✅
(The code above has 4 tests. In the GitHub repository you will find the complete test suite with 7 tests, including updates, deletes, and filtering — so if you run the repository, you will see 7.)
8. REST vs GraphQL: Same Project, Side by Side
Since we built the exact same project twice, we earned the right to a fair comparison:

| Aspect | REST version (DRF) | GraphQL version (Graphene) |
|---|---|---|
| Endpoints | /api/tasks/, /api/tasks/<id>/ | /graphql/ only |
| Code organization | serializers.py + views.py + urls.py | One schema.py |
| Response shape | Fixed (all fields, always) | Client chooses the fields |
| Interactive docs | Swagger (needed setup) | GraphiQL (came for free) |
| Testing tool | Postman / Swagger | GraphiQL in the browser |
| Learning curve | Familiar territory | New concepts (types, resolvers, mutations) |
My honest opinion after building both? For a small CRUD like this one, REST is simpler and perfectly fine — exactly as we concluded in the theory article. But now you have felt the difference in your fingers, and when a project with multiple clients and interconnected data appears in your life, you will know precisely which tool to reach for.
9. Conclusion
Today we rebuilt our task management API in GraphQL and, along the way, we saw the theory from the previous article come alive: the single endpoint, the client choosing fields, the auto-generated documentation, and friendly error handling with the ok + message pattern.
The complete project, with all 7 tests, is on my GitHub: https://github.com/mariomthree/task-management-graphql-api
Feel free to clone it, break it, improve it — and leave a star if it helped you! ⭐
Your thoughts matter! Did you prefer building this in REST or in GraphQL? Share your experience in the comments — and if something did not work on your machine, tell me and we will debug it together.
Thank you for reading, and see you in the next article! 👋
10. References
Django Software Foundation. (2026). Django documentation. https://docs.djangoproject.com/
Graphene Community. (2026). Graphene-Django documentation. https://docs.graphene-python.org/projects/django/
GraphQL Foundation. (2024). GraphQL documentation. https://graphql.org/
Mabande, M. M. (2025, September 9). Building a RESTful API with Python: Creating a simple task management. MarioM3. https://mariomthree.com/building-a-restful-api-with-python-creating-a-simple-task-management/
Mabande, M. M. (2026, July 20). GraphQL vs REST: When to choose each one. MarioM3. https://mariomthree.com/graphql-vs-rest/
GraphQL vs REST: When to Choose Each and Why It Matters
Introduction
GraphQL vs REST is one of the most common debates in modern API development — and by the end of this article, you will know exactly which one to choose.In our previous articles, we explored SOAP, REST, and even built a RESTful API with Python and Django REST Framework. As a result, we saw how REST replaced SOAP as the dominant style for web services. Its simplicity, statelessness, and use of standard HTTP methods made it the natural choice.
However, the story of APIs did not end with REST. In 2015, Facebook open-sourced a technology called GraphQL. Since then, one question keeps appearing in technical discussions and architecture meetings: should I use REST or GraphQL?
In this article, we will go beyond the basics. First, we will understand why GraphQL was created and which problems REST could no longer solve. Then, we will compare how each approach works in depth. After that, we will look at famous public APIs that use each one. Finally, I will share the books you should read to master both technologies.
1. A Quick Recap: What is REST?
As defined in our previous article, REST (Representational State Transfer) is an architectural style for networked applications. Roy Fielding introduced it in his doctoral dissertation, “Architectural Styles and the Design of Network-based Software Architectures” (Fielding, 2000).
In short, REST defines a set of constraints to achieve performance, scalability, and simplicity:
- Client-Server: separation between user interface and data storage;
- Stateless: each request contains all the information needed to process it;
- Cacheable: responses must define themselves as cacheable or not;
- Uniform Interface: resources have URIs and use standard HTTP methods (GET, POST, PUT, PATCH, DELETE);
- Layered System: the architecture can be composed of hierarchical layers.
Since the 2000s, REST has been the industry standard. In fact, according to Postman’s State of the API Report, it remains the most used style among developers today (Postman, 2023).
So, if REST works so well, why did Facebook feel the need to create something new?
2. The Problem: Why REST Was No Longer Enough for Facebook
To understand GraphQL, we need to go back to 2012. At that time, Facebook was rebuilding its native mobile applications, and the context matters:
- Smartphones were becoming the main way people accessed the internet;
- Mobile networks (especially 3G) were slow and unreliable, above all in developing countries;
- Facebook’s data model was deeply interconnected: users have friends, friends have posts, posts have comments, and comments have authors.
Because of this context, the engineering team — led by Lee Byron, Nick Schrock, and Dan Schafer — faced three structural problems with REST (Byron, 2015).

2.1 Over-fetching
REST endpoints return a fixed data structure defined by the server. For example, when the mobile app requested GET /users/123, it received the complete user object: name, email, birthday, hometown, and work history. Yet the screen only needed the name and the profile picture. On slow networks, every wasted byte meant a slower experience. Moreover, it meant higher data costs for the user.
2.2 Under-fetching and the N+1 Requests Problem
The opposite problem also existed. To render the News Feed, the app needed data from several resources: the user, their posts, the comments, and the comment authors. Consequently, REST forced multiple sequential round trips:
GET /users/123 → get the user
GET /users/123/posts → get their posts
GET /posts/1/comments → get comments of post 1
GET /posts/2/comments → get comments of post 2
...
Each round trip on a 3G network added latency. As a result, the app felt slow and users became frustrated.
2.3 Endpoint Proliferation and Versioning
To work around these limits, teams often created custom endpoints for specific screens, such as /users/123/newsfeed-mobile-v2. Over time, this produced dozens of endpoints that were hard to maintain and document. In addition, every design change in the app required backend changes and new API versions.
GraphQL was born as a direct answer to these three problems. It offers a single endpoint where the client — not the server — decides exactly which data it needs, in a single request.
3. What is GraphQL?
GraphQL is a query language for APIs and a server-side runtime that executes queries against a type system (GraphQL Foundation, 2024). Facebook developed it internally in 2012 and used it in production from 2013. Later, in 2015, the company open-sourced it. Today, the GraphQL Foundation, hosted by the Linux Foundation, governs the project.
One important clarification: GraphQL is not a database technology. It has no relation to graph databases like Neo4j. Instead, the “Graph” in the name refers to how it treats your data as a connected graph of objects.
Here is a simple analogy. Imagine ordering food at a restaurant:
- With REST, you order from a fixed menu. You ask for “Meal number 3” and receive everything in it — whether you wanted all of it or not.
- With GraphQL, you build your own plate. You tell the kitchen: “I want rice, chicken, and salad” — and that is exactly what you receive.
3.1 The Schema: The Contract Between Client and Server
Everything in GraphQL starts with the schema, written in the Schema Definition Language (SDL). The schema is strongly typed and works as a contract:
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
comments: [Comment!]!
}
type Comment {
id: ID!
text: String!
author: User!
}
The exclamation mark (!) means the field cannot be null. Thanks to this type system, we get powerful tooling: auto-completion, validation, and self-generated documentation.
3.2 Queries: Reading Data
A query is the equivalent of a GET in REST. However, the client specifies exactly which fields it wants:
query {
user(id: "123") {
name
posts(limit: 3) {
title
comments(limit: 2) {
text
author {
name
}
}
}
}
}
Notice what happened here. The entire News Feed problem from section 2.2 was solved in a single request. User, posts, comments, and authors — one round trip.
3.3 Mutations: Writing Data
Mutations create, update, or delete data. In other words, they are the equivalent of POST, PUT, PATCH, and DELETE:
mutation {
createPost(title: "GraphQL vs REST", content: "...") {
id
title
}
}
3.4 Subscriptions: Real-Time Data
Subscriptions let the client receive real-time updates from the server, usually via WebSockets:
subscription {
newComment(postId: "1") {
text
author {
name
}
}
}
3.5 Resolvers: Where the Logic Lives
On the server side, each field in the schema has a resolver — a function that fetches that specific piece of data. This is where GraphQL connects to your databases, microservices, or even existing REST APIs. In fact, a common migration strategy is to build a GraphQL layer on top of existing REST services.
4. GraphQL vs REST: In-Depth Comparison
| Aspect | REST | GraphQL |
|---|---|---|
| Endpoints | Multiple (one per resource) | Single (/graphql) |
| Data shape | Defined by the server | Defined by the client |
| Over-fetching | Common | Eliminated by design |
| Under-fetching | Requires multiple round trips | Solved with nested queries |
| Type system | Not built-in (OpenAPI is optional) | Mandatory, strongly typed schema |
| Versioning | Common practice (/v1, /v2) | Rarely needed (fields are deprecated, not removed) |
| HTTP caching | Native (GET + cache headers, CDNs) | Complex (queries use POST by default) |
| Error handling | HTTP status codes (404, 500…) | Always returns 200; errors in the response body |
| File uploads | Native (multipart/form-data) | Requires extensions or workarounds |
| Real-time | Requires polling or separate WebSockets | Built-in via Subscriptions |
| Learning curve | Low | Moderate |
| Server complexity | Low | Higher (query analysis, N+1, security) |
Here is an honest observation. GraphQL solves the N+1 problem on the network side, between client and server. However, it can bring the same problem back on the server side, between the API and the database, if resolvers are written naively. For this reason, tools like DataLoader exist. Facebook created it to solve this issue through batching and caching (Facebook, 2015).
5. Famous Public APIs: Who Uses What?
Theory is important. Even so, seeing real-world adoption gives us a better perspective.
5.1 Famous Public REST APIs
- Stripe API — considered by many the gold standard of REST design. It offers predictable resources, consistent errors, and excellent documentation (Stripe, 2024). Therefore, if you want to learn REST design, study Stripe.
- Twilio API — communications (SMS, voice, WhatsApp) built entirely on RESTful conventions.
- GitHub REST API (v3) — one of the most used APIs in the world, available since 2011.
- Spotify Web API — music catalog, playlists, and player control via REST.
- OpenWeatherMap API — a classic for beginners learning to consume APIs.
5.2 Famous Public GraphQL APIs
- GitHub GraphQL API (v4) — the most emblematic case. In 2016, GitHub announced that its next-generation API would use GraphQL. The reasons were exactly the over-fetching and endpoint proliferation problems we discussed (GitHub, 2016). Interestingly, the same company still maintains both styles: v3 (REST) and v4 (GraphQL).
- Shopify Storefront & Admin APIs — Shopify adopted a GraphQL-first strategy for e-commerce. As a result, each storefront requests only the product data it needs (Shopify, 2024).
- The Rick and Morty API — a free GraphQL API with no authentication. It is perfect for study and practice.
- Countries API — another free GraphQL API, ideal for your first queries.
- AniList API — an anime and manga database, fully GraphQL.

Notice the pattern. Companies with complex, connected data and many client types (GitHub, Shopify, Facebook) gravitate towards GraphQL. On the other hand, companies with clear, transactional resources (Stripe, Twilio) remain successfully on REST.
6. When to Choose REST
Based on everything we analysed, REST remains the right choice when:
- Your API is resource-oriented and CRUD-heavy. If your domain maps naturally to resources (tasks, users, products), REST’s simplicity is an advantage.
- HTTP caching is critical. REST GET requests are cacheable by browsers, CDNs, and proxies. In contrast, this is very hard to replicate with GraphQL.
- You are building a public API for third parties. REST’s universality lowers the entry barrier for external developers.
- Your team is small or the deadline is short. There is no schema to design and no resolvers to write.
- File uploads are a core feature. REST handles
multipart/form-datanatively.
7. When to Choose GraphQL
On the other hand, GraphQL becomes the better choice when its original problems are your problems:
- Multiple clients with different data needs. For instance, a web app, a mobile app, and a smartwatch app consuming the same API — each requesting only what it needs.
- Deeply interconnected data. If one screen needs data from 4 or 5 REST endpoints, GraphQL’s nested queries remove the extra round trips.
- Mobile-first products on unreliable networks. This was Facebook’s original motivation. Furthermore, it is especially relevant in our African context, where mobile data is expensive and networks are inconsistent.
- Fast-moving frontend teams. Frontend developers add fields to their queries without waiting for backend changes.
- Real-time features in the same API. Subscriptions provide a standard model for live updates.
Finally, remember: the two are not mutually exclusive. A common architecture uses REST for authentication, webhooks, and uploads, while GraphQL handles complex data fetching. After all, GitHub itself maintains both.
8. Conclusion
GraphQL did not appear to “kill” REST. Instead, it appeared because Facebook’s reality in 2012 — mobile clients, slow networks, connected data — exposed real limits in the fixed-endpoint model: over-fetching, under-fetching, and endpoint proliferation.
REST remains an excellent choice. It is simple, cacheable, and universal, and it still powers most of the world’s APIs. Meanwhile, GraphQL is a specialized tool that shines when data complexity and client diversity justify its extra server-side cost.
Therefore, before choosing, ask yourself:
- How interconnected is my data?
- How many client types will consume this API?
- How important is HTTP caching for my use case?
- Can my team manage a GraphQL server responsibly (query complexity, N+1, security)?
The honest answer to these four questions will point you in the right direction.
Have you used GraphQL in production? Do you prefer REST? Share your experience in the comments — your feedback matters and helps make these articles better!
Thank you for reading!
9. Recommended Books
Before the formal reference list, here is my suggested reading order:
To study REST: start with Richardson and Ruby (2007), the classic that popularized REST; then move to Richardson et al. (2013), its modernized successor; and keep Massé (2011) as a practical design rulebook. For the theoretical foundation, read Fielding’s (2000) original dissertation.
To study GraphQL: start with Porcello and Banks (2018), the best entry point for beginners; then Wieruch (2018) for a practical, project-based approach; and finish with Giroux (2020), written by a former GitHub engineer, to learn how to run GraphQL at scale in production.
10. References
Byron, L. (2015, September 14). GraphQL: A data query language. Engineering at Meta. https://engineering.fb.com/2015/09/14/core-infra/graphql-a-data-query-language/
Facebook. (2015). DataLoader [Computer software]. GitHub. https://github.com/graphql/dataloader
Fielding, R. T. (2000). Architectural styles and the design of network-based software architectures [Doctoral dissertation, University of California, Irvine]. https://ics.uci.edu/~fielding/pubs/dissertation/top.htm
GitHub. (2016, September 14). The GitHub GraphQL API. The GitHub Blog. https://github.blog/2016-09-14-the-github-graphql-api/
Giroux, M.-A. (2020). Production ready GraphQL. Self-published. https://book.productionreadygraphql.com/
GraphQL Foundation. (2024). GraphQL documentation. https://graphql.org/
Massé, M. (2011). REST API design rulebook. O’Reilly Media.
Porcello, E., & Banks, A. (2018). Learning GraphQL: Declarative data fetching for modern web apps. O’Reilly Media.
Postman. (2023). 2023 state of the API report. https://www.postman.com/state-of-api/
Richardson, L., Amundsen, M., & Ruby, S. (2013). RESTful web APIs: Services for a changing world. O’Reilly Media.
Richardson, L., & Ruby, S. (2007). RESTful web services. O’Reilly Media.
Shopify. (2024). Shopify API documentation. Shopify.dev. https://shopify.dev/docs/api
Stripe. (2024). Stripe API reference. https://stripe.com/docs/api
Wieruch, R. (2018). The road to GraphQL. Self-published. https://www.robinwieruch.de/the-road-to-graphql-book/
How to Protect Your WordPress Site: Essential Security Step-by-Step
Introduction
A website is the digital business card of any business or individual. To help protect this asset, this WordPress security guide was created to present best practices based on industry reports, ensuring visitors feel safe and data remains protected.
For this experience to be positive, it is essential that visitors feel safe — especially when the website is used for contact forms, user authentication, or e-commerce transactions. However, many basic security aspects are still neglected, leaving numerous websites vulnerable to attacks.
This article presents WordPress security best practices, based on reports and studies from recognised organisations in the field of cybersecurity.
1. Why focus on WordPress?
WordPress is currently the most widely used Content Management System (CMS) in the world, driven by its flexibility, large community, and extensive ecosystem of plugins and themes. However, this popularity also makes it one of the main targets of automated attacks (Wordfence, 2023).
It is important to note that the WordPress core itself is considered secure and is continuously audited by experts. Most security incidents are related to third-party plugins, themes, and poor maintenance practices (WPScan, 2024).
2. The first critical step: choosing themes and plugins
WordPress website security begins even before the site is published, during the selection of components to be installed.
2.1 Official and trusted sources
This is the golden rule. Installing a plugin or theme from untrusted sources is equivalent to granting administrative privileges to an unknown person. It is recommended to obtain themes and plugins only from recognised sources, such as:
- The official WordPress directory (WordPress.org)
- Reputable premium theme marketplaces (e.g., ThemeForest, Elegant Themes, StudioPress)
According to the WordPress Foundation (2024), the official directory undergoes continuous review processes, significantly reducing the risk of malicious code.
2.2 The risk of “nulled” themes
Finding a paid premium plugin available “for free” on unofficial websites is a major red flag. These themes and plugins, known as nulled (pirated versions), represent one of the greatest security risks, as they often contain:
- Backdoors
- Malicious scripts
- Code for spam distribution or traffic redirection
In addition, users lose access to critical security updates, leaving the website exposed to already known vulnerabilities (Kaspersky, 2023).
3. The reality of attacks: what the numbers say
The importance of WordPress security is supported by concrete data:
- More than 2,800 attacks per second target WordPress websites worldwide, mostly carried out by automated bots (HubSpot, 2023).
- Vulnerability reports indicate that over 95% of security flaws are related to plugins and themes, not the WordPress core itself (WPScan, 2024).
- According to Sucuri, more than 50% of infected WordPress websites were outdated at the time of the attack (Sucuri, 2022).
These figures show that most attacks could be prevented by adopting basic maintenance best practices.
4. Main causes of WordPress website compromise
Based on reports from specialised web security companies, the most common causes of successful attacks include:
- Outdated plugins and themes containing known vulnerabilities;
- Weak passwords and the absence of two-factor authentication (2FA), facilitating brute-force attacks;
- Vulnerabilities in popular plugins, widely exploited due to their high number of installations (Wordfence, 2023; Kaspersky, 2023).
5. Recommended plugins
| Objective | Recommended Plugin | Justification |
|---|---|---|
| General security | Wordfence Security | Acts as a firewall and intrusion detection system |
| Hide login page | WPS Hide Login | Changes the default admin login URL |
| Backup | UpdraftPlus | Enables fast website recovery in case of failure |
| 2FA authentication | WP 2FA | Adds an extra layer of security |
| Spam protection | Akismet | Automatically blocks spam comments and bots |
6. Essential protection measures
- Install only strictly necessary plugins and themes, avoiding excess;
- Remove inactive or unused plugins, even if they are disabled;
- Keep plugins, themes, and WordPress itself always up to date;
- Change the default login URL to reduce automated brute-force attacks;
- Limit the number of login attempts;
- Use two-factor authentication (2FA);
- Use services such as Cloudflare for firewall protection, bot mitigation, and SSL/TLS encryption (Cloudflare, 2024);
- Perform regular backups and store them outside the main server;
- Monitor logs and access reports to detect suspicious activity early.
7. Conclusion
WordPress security is not a one-time task, but a continuous process. Adopting practices such as regular updates, trusted sources, strong authentication, and external protection services significantly reduces the risk of security incidents.
Investing in digital security is a direct investment in a website’s credibility, availability, and trust.
8. References
Cloudflare. (2024). Cloudflare security overview. https://www.cloudflare.com
HubSpot. (2023). WordPress security issues and statistics. https://blog.hubspot.com
Kaspersky. (2023). Vulnerable WordPress plugins and themes. https://www.kaspersky.com
Sucuri. (2022). Website threat research report. https://sucuri.net
Wordfence. (2023). WordPress security report. https://www.wordfence.com
WPScan. (2024). WordPress vulnerability database. https://wpscan.com
WordPress Foundation. (2024). WordPress security. https://wordpress.org/about/security/





