diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da4fc702..857fa3bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## [Unreleased] +### Documentation +- Defining new API interface to fix security issue + [#1186](https://github.com/nextcloud/cookbook/pull/1186) @christianlupus ## 0.9.14 - 2022-08-29 diff --git a/docs/dev/api/0.1.0/index.html b/docs/dev/api/0.1.0/index.html new file mode 100644 index 000000000..6ddcad895 --- /dev/null +++ b/docs/dev/api/0.1.0/index.html @@ -0,0 +1,60 @@ + + + + + + Public API cookbook app + + + + + + + +
+ + + + + + diff --git a/docs/dev/api/0.1.0/internal-cookbook.yaml b/docs/dev/api/0.1.0/internal-cookbook.yaml new file mode 100644 index 000000000..32977d35f --- /dev/null +++ b/docs/dev/api/0.1.0/internal-cookbook.yaml @@ -0,0 +1,514 @@ +openapi: 3.0.1 +info: + title: Nextcloud cookbook app + description: >- + This is the internal API definition of the [cookbook app](https://github.com/nextcloud/cookbook) webapp for the [nextcloud server](http://nextcloud.com). + + + The total API is separated into two parts: + + - There is the public API part that can be used from 3rd party apps and scripts. + + - There is the internal API that is used only by the web app of the cookbook app. This is described here. + + + The internal part is intended only to be used by the internal web app. + It uses session based authentication and thus requires a `requesttoken` to protect against CSRF attacks. + The generation and updating of these tokens is not part of the app but the regular browser capabilities and the nextcloud web frontend is used here instead. + + + In contrast, the External APIs are intended for use by external services. + These endpoints require the user credentials to be present in every request. + Thus, no session is created and no cookies or similar needs to be handled. + Technically, there is a CORS preflight possible but it is not required for the function of the endpoints. + + + Further contact can be found on the matrix.org server in the room [#nextcloud-cookbook:matrix.org](https://matrix.to/#/#nextcloud-cookbook:matrix.org) for general questions. + Additionally, there is [#nextcloud-cookbook-integration:matrix.org](https://matrix.to/#/#nextcloud-cookbook-integration:matrix.org) for questions related to the API and third party integration. + Further information on the different versions can be found in [the API overview page](https://nextcloud.github.io/cookbook/dev/api/index). + #contact: + #email: apiteam@swagger.io + license: + name: AGPL-3 + url: 'http://www.gnu.org/licenses/agpl-3.0.de.html' + version: 0.1.0 + +#externalDocs: +# description: Find out more about Swagger +# url: 'http://swagger.io' + +servers: + - url: 'http://localhost:8000/apps/cookbook' + - url: '{protocol}://{server}' + variables: + protocol: + enum: + - http + - https + default: https + server: + default: 'example.com' + +tags: + # - name: External API v1 - Recipes + # description: Querying and manipulating recipes using external APIs + # - name: External API v1 - Categories + # description: Access to the categories of recipes using external APIs + # - name: External API v1 - Tags + # description: Access to tags/keywords of recipes using external APIs + # - name: External API v1 - Misc + # description: Other API endpoints for use by external APIs + + - name: Recipes + description: Everything related to recipes and their usage + - name: Categories + description: Access to the categories of the recipes + - name: Tags + description: Access to tags/keywords of recipes + - name: Misc + description: Other API endpoints + + + +components: + + schemas: + Config: + $ref: objects.yaml#/Config + Error: + $ref: objects.yaml#/Error + RecipeStub: + $ref: objects.yaml#/RecipeStub + StubList: + $ref: objects.yaml#/StubList + Recipe: + $ref: objects.yaml#/Recipe + + securitySchemes: + # app_password: + # type: http + # scheme: basic + # description: Use username and app password + requesttoken: + type: apiKey + name: requestkey + in: header + session: + type: apiKey + in: cookie + name: nc_session_id + +security: + - requesttoken: [] + session: [] + +paths: + + /webapp/reindex: + post: + tags: [ Misc ] + summary: Trigger a rescan of all recipes into the caching database + responses: + 200: + description: The reindex process was done. + content: + application/json: + schema: + type: string + example: Search index rebuilt successfully + /webapp/config: + get: + tags: [ Misc ] + summary: Get the current configuration of the app + responses: + 200: + description: The config was read successfully + content: + application/json: + schema: + $ref: "#/components/schemas/Config" + post: + tags: [ Misc ] + summary: Set the configuration for the current user + responses: + 200: + description: The configuration was successfully saved. + content: + application/json: + schema: + type: string + example: OK + + /webapp/import: + post: + tags: [ Recipes ] + summary: Import a recipe using schema.org metadata from a website + requestBody: + content: + application/json: + schema: + type: object + properties: + url: + type: string + example: 'http://www.chefkoch.de/2345' + required: + - url + responses: + 200: + description: Successfully imported recipe + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + 400: + description: The URL to be imported was not inserted in the request or any other issue was rosen. + content: + application/json: + schema: + type: string + example: Field "url" is required + 409: + description: There exists a recipe with that name already. Import was aborted. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /webapp/recipes/{id}/image: + get: + tags: [ Recipes ] + summary: Get the main image of a recipe. If no image is stored a fallback image is delivered. + parameters: + - in: path + name: id + description: The id of the recipe to obtain the image for. + required: true + schema: + type: integer + responses: + 200: + description: Image was obtained and will be in response either as image/jpeg or image/svg+xml + content: + image/jpeg: + schema: + type: string + format: binary + image/svg+xml: + schema: + type: string + format: binary + 406: + description: The recipe has no image whose MIME type matches the Accept header + /webapp/search/{query}: + parameters: + - in: path + name: query + required: true + description: The search string, urlencoded, separated with spaces and/or commas + schema: + type: string + get: + tags: [ Recipes ] + summary: Search for recipes for keywords, tags and categories with the named search string + responses: + 200: + description: The recipes were obtained successfully + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An error has been thrown + content: + application/json: + schema: + type: string + description: The error message + /webapp/recipes: + get: + tags: [ Recipes ] + summary: Get all recipes in the database + responses: + 200: + description: Successfully obtained all recipes + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + post: + tags: [ Recipes ] + summary: Create a new recipe + requestBody: + description: | + A JSON representation of the recipe to be saved. + + See also the structure at https://schema.org/Recipe + content: + application/json: + schema: + type: object + properties: + name: + type: string + required: [ "name" ] + additionalProperties: true + example: + name: "Chips" + description: "A very delicious way of getting kids quiet" + ingredients: + - "1 pack of pre-fried chips" + tools: ["common oven"] + instructions: + - "Put the chips in the oven" + - "Wait until the are due" + responses: + 200: + description: Successfully created new recipe + content: + application/json: + schema: + type: integer + example: 2462 + description: The id of the newly created recipe + 409: + description: A recipe with the name was already found on the server. No recipe is created. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + 422: + description: There was no name in the request given for the recipe. Cannot save the recipe. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /webapp/recipes/{id}: + parameters: + - in: path + name: id + required: true + description: The id of the recipe + schema: + type: integer + get: + tags: [ Recipes ] + summary: Get a single recipe from the server + responses: + 200: + description: Recipe was sucessfully obtained + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + 404: + description: The given recipe id was not found + content: + application/json: + schema: + type: integer + example: 2345 + description: The id of the recipe that was not found + put: + tags: [ Recipes ] + summary: Update a recipe + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + responses: + 200: + description: The recipe was sucessfully updated + content: + application/json: + schema: + type: integer + description: The id of the updated recipe + example: 2345 + 422: + description: There was no name in the request given for the recipe. Cannot save the recipe. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + delete: + tags: [ Recipes ] + summary: Delete an existing recipe + responses: + 200: + description: The recipe was deleted successfully + content: + application/json: + schema: + type: string + example: Recipe 2345 was deletes successfully + 502: + description: An Exception was thrown + content: + application/json: + schema: + type: string + example: Recipe with id 2345 was not found. + description: Error message + + /webapp/keywords: + get: + tags: [ Tags ] + summary: Get all known keywords + responses: + '200': + description: Successfully obtained all keywords + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + recipe_count: + type: integer + required: + - name + - recipe_count + example: + - name: vegetarian + recipe_count: 5 + - name: sugar-free + recipe_count: 2 + /webapp/tags/{keywords}: + get: + tags: [ Tags ] + summary: Get all recipes associated with certain keywords + parameters: + - in: path + name: keywords + required: true + description: Comma separated list of keywords, urlencoded + schema: + type: string + example: vegetarian,sweet + responses: + 200: + description: Recipes were successfully obtained + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An error occured + content: + application/json: + schema: + type: string + example: "SQLException: Something went wrong." + + /webapp/categories: + get: + tags: [ Categories ] + summary: Get all known categories + responses: + 200: + description: >- + Sucessfully obtained all categories + + + Please note: A category name of `*` indicates the number of + recipes with no category associated. + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + recipe_count: + type: integer + required: + - name + - recipe_count + example: + - name: Dinner + recipe_count: 21 + - name: Lunch + recipe_count: 10 + - name: '*' + recipe_count: 3 + /webapp/category/{category}: + get: + tags: [ Categories ] + summary: Get all recipes of a certain category + parameters: + - in: path + name: category + required: true + description: >- + The name of the category to be queried as urlencoded string + + + Put the string `_` to obtain all recipes with no category + schema: + type: string + responses: + 200: + description: The filtered recipes belonging to the category + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An exception was issued. + content: + application/json: + schema: + type: string + description: The error message + example: Could not find category foo. + put: + tags: [ Categories ] + summary: Rename a category + parameters: + - in: path + name: category + required: true + description: >- + The name of the category to be queried as urlencoded string + + + Put the string `_` to obtain all recipes with no category + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: Lunch + description: The new name to rename the category to + required: + - name + responses: + 200: + description: The category was renamed successfully + content: + application/json: + schema: + type: string + example: Lunch + 400: + description: The new category name was not included during the request. + 500: + description: The renaming did not succeed. + content: + application/json: + schema: + type: string + description: The error message + example: There exists already a category of that name. diff --git a/docs/dev/api/0.1.0/internal.html b/docs/dev/api/0.1.0/internal.html new file mode 100644 index 000000000..9d995803a --- /dev/null +++ b/docs/dev/api/0.1.0/internal.html @@ -0,0 +1,60 @@ + + + + + + Internal API of cookbook app + + + + + + + +
+ + + + + + diff --git a/docs/dev/api/0.1.0/objects.yaml b/docs/dev/api/0.1.0/objects.yaml new file mode 100644 index 000000000..cdbb09394 --- /dev/null +++ b/docs/dev/api/0.1.0/objects.yaml @@ -0,0 +1,382 @@ +Config: + type: object + description: An object describing the configuration of the web app + properties: + folder: + type: string + example: /Recipes + description: The folder in the user's files that contains the recipes + update_interval: + type: integer + example: 10 + description: The interval between automatic rescans to rebuild the database cache in minutes + print_image: + type: boolean + example: true + description: True, if the user wished to print the recipe images with the rest of the recipes + required: + - folder + - update_interval + - print_image + +Error: + type: object + description: An error description + properties: + msg: + type: string + description: The error message + example: Recipe could not be found + file: + type: string + description: The file in which the exception was thrown + example: /var/www/custom_apps/cookbook/Service/RecipeService.php + line: + type: integer + description: The line where the exception is thrown + example: 223 + +RecipeStubInformation: + type: object + description: The very basic information of a recipe + properties: + name: + type: string + description: The name of the recipe + example: Baked bananas + keywords: + type: string + description: A comma-separated list of recipe keywords, can be empty string + example: sweets,fruit + dateCreated: + type: string + description: The date the recipe was created in the app + example: "2022-01-02T16:12:41+0000" + dateModified: + type: string + description: The date the recipe was modified lastly in the app + example: "2022-01-10T10:02:52+0000" + imageUrl: + type: string + description: The URL of the recipe image + example: http://example.com/path/to/image.jpg + imagePlaceholderUrl: + type: string + description: The URL of the placeholder of the recipe image + example: http://example.com/path/to/image_thumb.jpg + required: + - "name" + - "keywords" + - "imageUrl" + - "imagePlaceholderUrl" + - "dateCreated" + +RecipeStub: + type: object + description: A stub of a recipe with some basic information present + allOf: + - $ref: "#/RecipeStubInformation" + - type: object + properties: + recipe_id: + type: integer + description: The index of the recipe + example: 1 + required: + - "recipe_id" + +StubList: + type: array + items: + $ref: "#/RecipeStub" + +Tool: + type: string + example: Flat and fire-resistent bowl + description: A single tool for a recipe. A tool is not consumed but only used. + +Ingredient: + type: string + example: 100g ripe Bananas + description: A single ingredient for a recipe + +Instruction: + type: string + example: Peel the bananas + description: An instruction step for processing the recipe + +Nutrition: + type: object + properties: + "@type": + type: string + example: NutritionInformation + description: Schema.org object description + calories: + type: string + description: The number of calories for the given amount + example: 650 kcal + carbohydrateContent: + type: string + description: The number of grams of carbohydrates + example: 300 g + cholesterolContent: + type: string + description: The number of milligrams of cholesterol + example: 10 g + fatContent: + type: string + description: The number of grams of fat + example: 45 g + fiberContent: + type: string + description: The number of grams of fiber + example: 50 g + proteinContent: + type: string + description: The number of grams of protein + example: 80 g + saturatedFatContent: + type: string + description: The number of grams of saturated fat + example: 5 g + servingSize: + type: string + description: The serving size, in terms of the number of volume or mass + example: One plate, sufficient for one person as dessert + sodiumContent: + type: string + description: The number of milligrams of sodium + example: 10 mg + sugarContent: + type: string + description: The number of grams of sugar + example: 5 g + transFatContent: + type: string + description: The number of grams of trans fat + example: 10 g + unsaturatedFatContent: + type: string + description: The number of grams of unsaturated fat + example: 40 g + required: + - "@type" + +Recipe: + #type: object + description: A recipe according to [schema.org](http://schema.org/Recipe) + allOf: + - $ref: "#/RecipeStubInformation" + - type: object + properties: + "@type": + type: string + example: "Recipe" + description: Schema.org object type identifier + id: + type: integer + description: The index of the recipe + example: 123 + prepTime: + type: string + nullable: true + description: The time required for preparation in ISO8601 format + example: "PT0H10M" + cookTime: + type: string + nullable: true + description: The time required for cooking in ISO8601 format + example: "PT1H20M" + totalTime: + type: string + nullable: true + description: The time required for the complete processing in ISO8601 format + example: "PT1H30M" + description: + type: string + example: A very easy way to make children happy + description: A description of the recipe or the empty string + url: + type: string + example: http://exmaple.com/my-recipe.html + description: The URL the recipe was found at or the empty string + image: + type: string + example: http://example.com/my-recipe-image.jpeg + description: The URL of the original recipe + recipeYield: + type: integer + example: 4 + description: Number of servings in recipe + recipeCatregory: + type: string + example: Dessert + description: The category of the recipe + tools: + type: array + items: + $ref: "#/Tool" + recipeIngredients: + type: array + items: + $ref: "#/Ingredient" + recipeInstructions: + type: array + items: + $ref: "#/Instruction" + nutrition: + $ref: "#/Nutrition" + required: + - id + - prepTime + - cookTime + - totalTime + - description + - url + - recipeYield + - recipeCategory + - tools + - recipeIngredients + - recipeInstructions + - nutrition + additionalProperties: true + example: + name: Baked bananas + id: 123 + description: A very delightful recipe of the best baked bananas ever + image: http://example.com/path/to/image.jpg + recipeYield: 5 + prepTime: PT0H15M + cookTime: null + totalTime: PT1H20M + url: '' + tools: [] + recipeIngredient: + - 3 ripe bananas + - 100g sugar + - 20 teaspoons of cinamon + resipeInstructions: + - Peel the bananas + - Dip the bananas in the pot of sugar + - Put the banans in the oven and let the cinamon soak in for 10 minutes + - After 5 hours of baking, they are ready + recipeCategory: Dessert + keywords: banana,cinnamon,sweet,untested recipe + nutrition: [] + +RecipeList: + type: array + items: + $ref: "#/Recipe" + example: + - name: Baked bananas + description: A very delightful recipe of the best baked bananas ever + image: http://example.com/path/to/image.jpg + recipeYield: 5 + prepTime: PT0H15M + recipeIngredient: + - 3 ripe bananas + - 100g sugar + - 20 teaspoons of cinamon + resipeInstructions: + - Peel the bananas + - Dip the bananas in the pot of sugar + - Put the banans in the oven and let the cinamon soak in for 10 minutes + - After 5 hours of baking, they are ready + recipeCategory: Dessert + keywords: banana,cinnamon,sweet,untested recipe + - name: "Homemade Apple Butter" + author: + "@type": Person + name: "Julie Clark" + description: "A simple recipe for Homemade Apple Butter that you can make in the slow cooker. Use as a spread, a syrup or in your fall recipes!" + datePublished: "2016-09-01T01:58:54+00:00" + image: "https://www.tastesoflizzyt.com/wp-content/uploads/2016/08/homemade-apple-butter-2-480x270.jpg" + recipeYield: 20 + prepTime: "PT0H25M" + cookTime: "PT10H0M" + totalTime: "PT10H25M" + recipeIngredient: + - 6 1/2 pounds apples (peeled, cored and sliced) + - 1/2 cup granulated sugar + - 1/2 cup packed brown sugar + - 1 1/2 tablespoons ground cinnamon + - 1/4 teaspoon salt + - 1 tablespoon vanilla extract + recipeInstructions: + - Place the apples in a slow cooker. + - Add the sugars, cinnamon, salt and vanilla to the crockpot. Mix well. + - Cook in slow cooker on low for about 10 hours, stirring every couple hours. The apple butter should be thick and dark brown. + - If desired, use a blender to puree the apple butter until smooth. + - Cover and refrigerate for up to two weeks or freeze in small containers. + aggregateRating: + "@type": "AggregateRating" + ratingValue: "4.87" + ratingCount: "38" + recipeCategory: "Breakfast" + keywords: "apple butter recipes,apple recipes,fall recipes" + nutrition: + "@type": "NutritionInformation" + calories: "120 kcal" + carbohydrateContent: "31 g" + sodiumContent: "32 mg" + fiberContent: "3 g" + sugarContent: "25 g" + servingSize: "1 serving" + tool: [] + url: "https://www.tastesoflizzyt.com/homemade-apple-butter/" + dateModified: "2021-05-23T17:10:25+0000" + dateCreated: "2021-05-23T17:10:25+0000" + +ReleaseVersion: + type: array + items: + type: integer + minItems: 3 + maxItems: 3 + description: The installed release of the cookbook app + example: [0, 9, 14] + +PreReleaseVersion: + type: array + items: + type: integer|string + minItems: 4 + maxItems: 4 + description: The installed pre-release of the cookbook app + example: [0, 9, 14, "-rc1"] + +AppVersion: + oneOf: + - $ref: "#/ReleaseVersion" + - $ref: "#/PreReleaseVersion" + +APIVersion: + type: object + properties: + epoch: + type: integer + description: An epoch to cope with bad API versions + major: + type: integer + description: The major number of the API + minor: + type: integer + description: The minor number of the API + required: + - "epoch" + - "major" + - "minor" + example: + epoch: 0 + major: 1 + minor: 3 + +Version: + type: object + properties: + cookbook_version: + $ref: "#/AppVersion" + api_version: + $ref: "#/APIVersion" diff --git a/docs/dev/api/0.1.0/openapi-cookbook.yaml b/docs/dev/api/0.1.0/openapi-cookbook.yaml new file mode 100644 index 000000000..1b8bfcb88 --- /dev/null +++ b/docs/dev/api/0.1.0/openapi-cookbook.yaml @@ -0,0 +1,508 @@ +openapi: 3.0.1 +info: + title: Nextcloud cookbook app + description: >- + This is the public API definition of the [cookbook app](https://github.com/nextcloud/cookbook) for the [nextcloud server](http://nextcloud.com). + + + The total API is separated into two parts: + + - There is the public API part that can be used from 3rd party apps and scripts. + + - There is the internal API that is used only by the web app of the cookbook app. This is described here. + + + The internal part is intended only to be used by the internal web app. + It uses session based authentication and thus requires a `requesttoken` to protect against CSRF attacks. + The generation and updating of these tokens is not part of the app but the regular browser capabilities and the nextcloud web frontend is used here instead. + + + In contrast, the External APIs are intended for use by external services. + These endpoints require the user credentials to be present in every request. + Thus, no session is created and no cookies or similar needs to be handled. + Technically, there is a CORS preflight possible but it is not required for the function of the endpoints. + + + Further contact can be found on the matrix.org server in the room [#nextcloud-cookbook:matrix.org](https://matrix.to/#/#nextcloud-cookbook:matrix.org) for general questions. + Additionally, there is [#nextcloud-cookbook-integration:matrix.org](https://matrix.to/#/#nextcloud-cookbook-integration:matrix.org) for questions related to the API and third party integration. + Further information on the different versions can be found in [the API overview page](https://nextcloud.github.io/cookbook/dev/api/index). + #contact: + #email: apiteam@swagger.io + license: + name: AGPL-3 + url: 'http://www.gnu.org/licenses/agpl-3.0.de.html' + version: 0.1.0 + +#externalDocs: +# description: Find out more about Swagger +# url: 'http://swagger.io' + +servers: + - url: 'http://localhost:8000/apps/cookbook' + - url: '{protocol}://{server}' + variables: + protocol: + enum: + - http + - https + default: https + server: + default: 'example.com' + +tags: + - name: Recipes + description: Everything related to recipes and their usage + - name: Categories + description: Access to the categories of the recipes + - name: Tags + description: Access to tags/keywords of recipes + - name: Misc + description: Other API endpoints + + + +components: + schemas: + Config: + $ref: objects.yaml#/Config + Error: + $ref: objects.yaml#/Error + RecipeStub: + $ref: objects.yaml#/RecipeStub + StubList: + $ref: objects.yaml#/StubList + Recipe: + $ref: objects.yaml#/Recipe + Version: + $ref: objects.yaml#/Version + + securitySchemes: + app_password: + type: http + scheme: basic + description: Use username and app password + +security: + - app_password: [] + +paths: + + /api/version: + get: + tags: [ Misc ] + summary: Get the version of the API endpoint + responses: + '200': + description: API version + content: + application/json: + schema: + $ref: "#/components/schemas/Version" + /api/v1/reindex: + post: + tags: [ Misc ] + summary: Trigger a rescan of all recipes into the caching database + responses: + 200: + description: The reindex process was done. + content: + application/json: + schema: + type: string + example: Search index rebuilt successfully + /api/v1/config: + get: + tags: [ Misc ] + summary: Get the current configuration of the app + responses: + 200: + description: The config was read successfully + content: + application/json: + schema: + $ref: "#/components/schemas/Config" + post: + tags: [ Misc ] + summary: Set the configuration for the current user + responses: + 200: + description: The configuration was successfully saved. + content: + application/json: + schema: + type: string + example: OK + + /api/v1/import: + post: + tags: [ Recipes ] + summary: Import a recipe using schema.org metadata from a website + requestBody: + content: + application/json: + schema: + type: object + properties: + url: + type: string + example: 'http://www.chefkoch.de/2345' + required: + - url + responses: + 200: + description: Successfully imported recipe + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + 400: + description: The URL to be imported was not inserted in the request or any other issue was rosen. + content: + application/json: + schema: + type: string + example: Field "url" is required + 409: + description: There exists a recipe with that name already. Import was aborted. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /api/v1/recipes/{id}/image: + get: + tags: [ Recipes ] + summary: Get the main image of a recipe. If no image is stored a fallback image is delivered. + parameters: + - in: path + name: id + description: The id of the recipe to obtain the image for. + required: true + schema: + type: integer + responses: + 200: + description: Image was obtained and will be in response either as image/jpeg or image/svg+xml + content: + image/jpeg: + schema: + type: string + format: binary + image/svg+xml: + schema: + type: string + format: binary + 406: + description: The recipe has no image whose MIME type matches the Accept header + /api/v1/search/{query}: + parameters: + - in: path + name: query + required: true + description: The search string, urlencoded, separated with spaces and/or commas + schema: + type: string + get: + tags: [ Recipes ] + summary: Search for recipes for keywords, tags and categories with the named search string + responses: + 200: + description: The recipes were obtained successfully + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An error has been thrown + content: + application/json: + schema: + type: string + description: The error message + /api/v1/recipes: + get: + tags: [ Recipes ] + summary: Get all recipes in the database + responses: + 200: + description: Successfully obtained all recipes + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + post: + tags: [ Recipes ] + summary: Create a new recipe + requestBody: + description: | + A JSON representation of the recipe to be saved. + + See also the structure at https://schema.org/Recipe + content: + application/json: + schema: + type: object + properties: + name: + type: string + required: [ "name" ] + additionalProperties: true + example: + name: "Chips" + description: "A very delicious way of getting kids quiet" + ingredients: + - "1 pack of pre-fried chips" + tools: ["common oven"] + instructions: + - "Put the chips in the oven" + - "Wait until the are due" + responses: + 200: + description: Successfully created new recipe + content: + application/json: + schema: + type: integer + example: 2462 + description: The id of the newly created recipe + 409: + description: A recipe with the name was already found on the server. No recipe is created. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + 422: + description: There was no name in the request given for the recipe. Cannot save the recipe. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /api/v1/recipes/{id}: + parameters: + - in: path + name: id + required: true + description: The id of the recipe + schema: + type: integer + get: + tags: [ Recipes ] + summary: Get a single recipe from the server + responses: + 200: + description: Recipe was sucessfully obtained + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + 404: + description: The given recipe id was not found + content: + application/json: + schema: + type: integer + example: 2345 + description: The id of the recipe that was not found + put: + tags: [ Recipes ] + summary: Update a recipe + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Recipe" + responses: + 200: + description: The recipe was sucessfully updated + content: + application/json: + schema: + type: integer + description: The id of the updated recipe + example: 2345 + 422: + description: There was no name in the request given for the recipe. Cannot save the recipe. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + delete: + tags: [ Recipes ] + summary: Delete an existing recipe + responses: + 200: + description: The recipe was deleted successfully + content: + application/json: + schema: + type: string + example: Recipe 2345 was deletes successfully + 502: + description: An Exception was thrown + content: + application/json: + schema: + type: string + example: Recipe with id 2345 was not found. + description: Error message + + /api/v1/keywords: + get: + tags: [ Tags ] + summary: Get all known keywords + responses: + '200': + description: Successfully obtained all keywords + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + recipe_count: + type: integer + required: + - name + - recipe_count + example: + - name: vegetarian + recipe_count: 5 + - name: sugar-free + recipe_count: 2 + /api/v1/tags/{keywords}: + get: + tags: [ Tags ] + summary: Get all recipes associated with certain keywords + parameters: + - in: path + name: keywords + required: true + description: Comma separated list of keywords, urlencoded + schema: + type: string + example: vegetarian,sweet + responses: + 200: + description: Recipes were successfully obtained + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An error occured + content: + application/json: + schema: + type: string + example: "SQLException: Something went wrong." + + /api/v1/categories: + get: + tags: [ Categories ] + summary: Get all known categories + responses: + 200: + description: >- + Sucessfully obtained all categories + + + Please note: A category name of `*` indicates the number of + recipes with no category associated. + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + recipe_count: + type: integer + required: + - name + - recipe_count + example: + - name: Dinner + recipe_count: 21 + - name: Lunch + recipe_count: 10 + - name: '*' + recipe_count: 3 + /api/v1/category/{category}: + get: + tags: [ Categories ] + summary: Get all recipes of a certain category + parameters: + - in: path + name: category + required: true + description: >- + The name of the category to be queried as urlencoded string + + + Put the string `_` to obtain all recipes with no category + schema: + type: string + responses: + 200: + description: The filtered recipes belonging to the category + content: + application/json: + schema: + $ref: "#/components/schemas/StubList" + 500: + description: An exception was issued. + content: + application/json: + schema: + type: string + description: The error message + example: Could not find category foo. + put: + tags: [ Categories ] + summary: Rename a category + parameters: + - in: path + name: category + required: true + description: >- + The name of the category to be queried as urlencoded string + + + Put the string `_` to obtain all recipes with no category + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: Lunch + description: The new name to rename the category to + required: + - name + responses: + 200: + description: The category was renamed successfully + content: + application/json: + schema: + type: string + example: Lunch + 400: + description: The new category name was not included during the request. + 500: + description: The renaming did not succeed. + content: + application/json: + schema: + type: string + description: The error message + example: There exists already a category of that name. diff --git a/docs/dev/api/changelog/0.md b/docs/dev/api/changelog/0.md index 4b0f2c3ce..a63975934 100644 --- a/docs/dev/api/changelog/0.md +++ b/docs/dev/api/changelog/0.md @@ -8,6 +8,16 @@ This serves only for developers to find the changes better. ## Unpublished +### Split and rename API endpoints +There is a security issue with the previous API version 0.4.0, see [this description](https://github.com/nextcloud/cookbook/issues/1179). +As a result, **all** endpoints need a renaming to be able to fix the security issue. + +All publicly available endpoints are now located under the `/api/v1` prefix. +Endpoints were prefixed with either `/api/v1` (if not already prefixed by `/api`) or the `/api` was replaced by `/api/v1` in all URLs. + +The behavior of the endpoints was not changed. + + ## Version 0.0.4 - cookbook v0.9.13 - 2022-07-02 See [API specification](../0.0.4/index.html) diff --git a/docs/dev/api/index.md b/docs/dev/api/index.md index d4d20af70..52b3a186d 100644 --- a/docs/dev/api/index.md +++ b/docs/dev/api/index.md @@ -5,6 +5,7 @@ This page provides an overview over the possible API endpoints provided by the a - [Version 0.0.2](0.0.2/index.html) - [Version 0.0.3](0.0.3/index.html) - [Version 0.0.4](0.0.4/index.html) +- [Version 0.1.0](0.1.0/index.html) ([internal interface](0.1.0/internal.html)) The following list provides a in depth changelog for the individual epochs: diff --git a/docs/dev/deployment.md b/docs/dev/deployment.md index 3e33a750f..7fadf0bf5 100644 --- a/docs/dev/deployment.md +++ b/docs/dev/deployment.md @@ -24,7 +24,7 @@ So you might want to create a branch `release/1.2.4` from master. git checkout -b release/1.2.4 master ``` -### Update the changelog +### Update the changelogs In the release branch you will have to prepare the changelog file. This means, you have to add a new second level heading to the unreleased changes so far. @@ -34,6 +34,9 @@ You might need to add ``` as one of the first few lines with `YYYY-mm-dd` the current date. +Also check if any pending API change is present. +Update the API changelog (in `/docs/dev/api/changelog/*.md`) accordingly. + Commit the changes and push them to github. ### Create pull request