3. REST API endpoint
REST API endpoint
This file was copied from the packages/webapp/src/stories/docs
folder. Its accuracy as of August 8, 2024 has not been verified
Many endpoints are not following LiteFarm API naming conventions. Please reach out to Kike if you have doubt.
| Resources | | --------- | | Express routing | | LiteFarm REST API styleguide |
1. Create new endpoints
Create endpoints to access/modify data in a new table
Go to directory /packages/api/routes and create a new file newTalbeNameRoute.js
.
Copy the following template into the new file.
hasFarmAccess
middleware and checkScope
middleware are used for authorization, which will be covered by MiddleWare. Leave them as-is for now.
const express = require('express');
const router = express.Router();
const { getNewEntitiesByFarmId, getNewEntityByNewEntityId, deleteNewEntity, createNewEntity,
updateNewEntity } = require('../controllers/newEntityController');
const checkScope = require('../middleware/acl/checkScope');
const hasFarmAccess = require('../middleware/acl/hasFarmAccess');
router.get('/farm/:farm_id', hasFarmAccess({ params: 'farm_id' }), checkScope(['get:new_entity']),
getNewEntitiesByFarmId());
router.get('/:new_entity_id', hasFarmAccess({ params: 'new_entity_id' }), checkScope(['get:new_entity']),
getNewEntityByNewEntityId());
router.delete('/:new_entity_id', hasFarmAccess({ params: 'new_entity_id' }), checkScope(['delete:new_entity']),
deleteNewEntity());
router.post('/', hasFarmAccess({ body: 'farm_id' }), checkScope(['add:new_entity']),
createNewEntity());
router.put('/:new_entity_id', hasFarmAccess({ params: 'new_entity_id' }), checkScope(['edit:new_entity']),
updateNewEntity());
module.exports = router;
Copy
Open api/src/server.js
, import created file newTalbeNameRoute.js
, and attach new endpoints to express server.
const newEntityRoutes = require('./routes/newTalbeNameRoute');
const app = express();
app.use('/new_entity', newEntityRoutes);
Copy
Users will then be able to get new entities by accessing domain.org/new_entity/farm/farm_id
;
Please refer to LiteFarm REST API styleguide for naming convention
In short, endpoints should follow /new_entity_table_name/new_entity_id
for single pk and /composite_table_name/parent_table_name/parent_id/child_table_name/child_id
for composite pk
A composite key example would be /user_farm/farm/farm_id/user/user_id
where a farm has many owners/managers/extension officers/workers
2. Create empty controllers
Create a new file api/src/controller/newEntityController.js
and copy the following template
const NewEntityModel = require('../models/newEntityModel');
const newEntityController = {
getNewEntitiesByFarmId() {
return async (req, res, next) => {
const { farm_id } = req.params;
try{
const result = await NewEntityModel.query().where();
return result?.length ? res.status(200).send(result): res.status(404).send('New entities not found');
}catch(error){
return res.status(400).json({ error });
}
}
},
getNewEntityByNewEntityId() {
return async (req, res, next) => {
const { new_entity_id } = req.params;
try{
const result = await NewEntityModel.query().where();
return result ? res.status(200).send(result): res.status(404).send('New entity not found');
}catch(error){
return res.status(400).json({ error });
}
}
},
deleteNewEntity() {
return async (req, res, next) => {
const { new_entity_id } = req.params;
try {
const result = await NewEntityModel.query().where();
return result ? res.sendStatus(200): res.status(404).send('New entity not found');
} catch (error) {
return res.status(400).json({ error });
}
}
},
createNewEntity(asset) {
return async (req, res, next) => {
try {
const result = await NewEntityModel.query().where();
return res.status(201).send(result);
} catch (error) {
return res.status(400).json({ error });
}
}
},
updateNewEntity(asset) {
return async (req, res, next) => {
const { new_entity_id } = req.params;
try {
const result = await NewEntityModel.query().where();
return result ? res.status(200).send(result): res.status(404).send('New entity not found');
} catch (error) {
return res.status(400).send({ error });
}
}
},
}
module.exports = newEntityController;
Copy
Please refer to LiteFarm REST API styleguide for status status code convention
In short, post
success should return status code 201
.
get
delete
patch
put
success should return status code 200
.
If no entity is found, return status code 404
.
Validation errors should return status code 400
.
Authorization (role permission) errors should return status code 403
.
Authentication (invalid jwt) error should return error code 401
Steps for a backend - frontend story from a data flow perspective
Create knex migration to create/modify tables in database
Create objection models
Endpoints and empty controllers
Backend jest unit testing
Implement controllers
Create authorization/validation middlewares
Run tests and make sure everything passes
Create pure frontend components in storybook
res.data normalizer, redux slice, redux selectors to hold and access the data
Redux saga for get/post/put/patch request
Container component to connect saga actions/selector with pure components
Connect Route component with container components with react router
Manual testing