-
-
Notifications
You must be signed in to change notification settings - Fork 725
API Development
This page contains important information if you are a dev planning to improve the OFN API in some way.
The OFN API is implemented in a specific namespace /api. There are quite a few endpoints that are not under /api that render json, particularly in /admin (where they are mixed with html rendering endpoints). We do not consider these endpoints as part of the OFN API.
AMS is the serialization solution used in the OFN API, that means we stopped using rabl files in OFN. In OFN codebase, there should be no API code under app/views because AMS serializers should all be under /app/serializers.
To build a new API endpoint, first, you need to check what endpoint or action you what to add. There's a API specific routes file for API routes here.
We will use api/products/bulk_products as our "good" example, you can see this endpoint is a specific GET endpoint in the api routes file here.
Some comments about this example api/products/bulk_products endpoint:
- this could be the default index endpoint in the main /products route but because it's returning "products the user can edit" and not "all products the user can see", it's acceptable to have it in a different url, in this case api/products/bulk_products
- the name bulk refers to the client page (bulk products edit page) that uses this endpoint, ideally this should not be the case, the endpoint should only refer to the data it returns, not its clients. In this case a better name would be for example api/products/editable.
All API controllers are now under app/controllers/api here.
We can find our example bulk_products action in the api/products_controller.rb here.
In this products controller you will also find typical actions implemented:
- show - GET /api/products/{product_id} - gets one product
- create - POST /api/products - creates a product with given details
- update - GET /api/products/{product_id} - updates a product with given details
- destroy - DELETE /api/products/{product_id} - deletes a product with given Id
- index (not present in this case) - GET /api/products - lists products
In order to create the results for your endpoint, you should use AMS Serializers, you can re-use existing ones, they are all under app/serializers/api here, or you can create new ones in the same folder.
Note about serializers usage: a lot of these serializers are used outside the API: they are used to render json data that is injected in the DOM of the pages rendered. For example, a list of enterprises is injected in the checkout page's DOM here using the Api::EnterpriseSerializer.
Note about the admin namespace: currently we have two namespaces app/serializers/api and app/serializers/api/admin. The api/admin folder contains serarializers for the admin side of the OFN app but it's not consistent... there's no admin namespace in the API itself and the API uses both serializers from serializers/api/ and serializers/api/admin...
A note about managing Serializers: we should keep the number of serializers to a minimum, make sure you really need a new serializer when you create one and that you cannot adapt an existing one to your needs. In some cases, you will need a specific serializer for the same entity, we dont have conventions for this yet but try to make these generic if possible, see for example enterprise_thin_serializer, the enterprise_serializer and the basic_enterprise_serializer. This is not simple but necessary for enterprises. There's a discussion about this challenge here in discourse.
In OFN we use kaminari for pagination.
You can check the products/bulk_product pagination code for reference. Basically, the query string can include ?page=1&per_page=15 and the result object can be filtered with the .page and .per methods, see another example in the orders index search.
The pagination data in the payload should follow this structure.
For filtered lists we use ransack.
This search will be done on the index action typically.
The filters will be sent through the query parameters and encoded under the q parameter, like this example:
?q%5Bbill_address_firstname_start%5D=Luis&q%5Bbill_address_lastname_start%5D=Ramos&q%5Bcompleted_at_not_null%5D=true&q%5Bemail_cont%[email protected]&q%5Bs%5D=completed_at+desc
This will enable us to simply filter results using ransack and params[:q] like here.
All PRs that make a change to the API should also make a change to the swagger doc so that the documentation evolves with the code. To do this you can:
- use swagger to open the swagger doc: https://github.com/openfoodfoundation/openfoodnetwork/blob/master/swagger.yaml
- update the docs according to the changes in your PR
- export the changes to a file and include that new swagger.yml file with your changes in the PR
Development environment setup
- Pipeline development process
- Bug severity
- Feature template (epic)
- Internationalisation (i18n)
- Dependency updates
Development
- Developer Guidelines
- The process of review, test, merge and deploy
- Making a great commit
- Making a great pull request
- Code Conventions
- Database migrations
- Testing and Rspec Tips
- Automated Testing Gotchas
- Rubocop
- Angular and OFN
- Feature toggles
- Stimulus and Turbo
Testing
- Testing process
- OFN Testing Documentation (Handbooks)
- Continuous Integration
- Parallelized test suite with knapsack
- Karma
Releasing
Specific features
Data and APIs
Instance-specific configuration
External services
Design