Strapi auto-generates a full REST and GraphQL API from your content types — and it's the most popular open-source headless CMS.
Content Type Builder
Define your schema in the admin panel or code:
// src/api/post/content-types/post/schema.json
{
"kind": "collectionType",
"collectionName": "posts",
"attributes": {
"title": { "type": "string", "required": true },
"content": { "type": "richtext" },
"slug": { "type": "uid", "targetField": "title" },
"cover": { "type": "media" },
"category": { "type": "relation", "relation": "manyToOne", "target": "api::category.category" },
"tags": { "type": "relation", "relation": "manyToMany", "target": "api::tag.tag" },
"publishedAt": { "type": "datetime" }
}
}
Auto-Generated REST API
# List with filters, sort, pagination, populate
GET /api/posts?filters[category][name][$eq]=tech&sort=publishedAt:desc&pagination[page]=1&pagination[pageSize]=10&populate=*
# Single entry
GET /api/posts/1?populate[category]=*&populate[tags]=*
# Create
POST /api/posts
{ "data": { "title": "New Post", "content": "...", "category": 1 } }
# Update
PUT /api/posts/1
{ "data": { "title": "Updated Title" } }
# Delete
DELETE /api/posts/1
Custom Controllers
// src/api/post/controllers/post.js
module.exports = {
async findFeatured(ctx) {
const posts = await strapi.entityService.findMany('api::post.post', {
filters: { featured: true },
sort: { publishedAt: 'desc' },
limit: 5,
populate: ['cover', 'category']
})
return posts
}
}
// src/api/post/routes/custom.js
module.exports = {
routes: [
{ method: 'GET', path: '/posts/featured', handler: 'post.findFeatured' }
]
}
Middleware & Policies
// src/api/post/policies/is-owner.js
module.exports = async (ctx, config, { strapi }) => {
const post = await strapi.entityService.findOne('api::post.post', ctx.params.id, {
populate: ['author']
})
if (post.author.id !== ctx.state.user.id) {
return ctx.unauthorized('You can only edit your own posts')
}
return true
}
Webhooks
Configure in admin panel: trigger HTTP requests when content changes. Perfect for:
- Rebuild static site on publish
- Invalidate CDN cache
- Sync to search index
- Send notifications
Real-World Use Case
A startup needed a content API for their React Native app + marketing website. Options: build custom (weeks), WordPress REST API (slow, bloated), or Strapi. They chose Strapi: 30 minutes to define content types, instant REST API, admin panel for content editors. Two years later, same Strapi instance serves mobile app, web app, and internal tools.
Strapi is the Node.js API generator disguised as a CMS.
Build Smarter Data Pipelines
Need to scrape websites, extract APIs, or automate data collection? Check out my ready-to-use scrapers on Apify — no coding required.
Custom scraping solution? Email me at spinov001@gmail.com — fast turnaround, fair prices.
Top comments (0)