-
-
Notifications
You must be signed in to change notification settings - Fork 729
API documentation
This page describes Open Food Network's API (this page has been rebuilt in Sept 2019 as part of the issue #3001).
OFN API is no longer based on Spree's API and only includes OFN specific endpoints.
We use swagger and json-api to document the OFN API. You can see the documentation here: https://app.swaggerhub.com/apis/luisramos0/the-open_food_network/0.1
To access the API, you need an API key. This can be found in the admin
backend at the right of the edit user page. That can be passed with the
X-Spree-Token
request header, or the token
query parameter.
The user api key can be found in the OFN backoffice: click on the menu Users, select the user that will use the API, see "API KEY".
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 that uses this endpoint, ideally this should not be the case the 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/api/serializers 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.
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 I dont think this is 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. 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.
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%5D=[email protected]&q%5Bs%5D=completed_at+desc
This will enable us to simply filter results using ransack and params[:q] like here.
Regarding input data for POST and PUT endpoints where client will send data to create or update resources. This data is currently being sent via form_data. We should probably switch all our endpoints to take json data from clients instead.
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