AWS SAM Lambda Model Validation Not Working - aws-api-gateway

I'm currently attempting to perform validation on input requests.
Models:
PutStepPlanCRUDModel:
description: "The model for PUT StepPlanCRUD"
type: object
$schema: "http://json-schema.org/draft-04/schema#"
required:
- payload
properties:
payload:
type: object
required:
- updated_fields
additionalProperties: false
properties:
updated_fields:
type: object
additionalProperties: false
minProperties: 1
properties:
step_plan_name:
type: string
description: "The name of the step plan"
step_records:
type: object
additionalProperties: false
It appears as thought the required validation is working however the following validations are not:
additionalProperties: false
minProperties: 1
I'd like to be able to allow the two fields step_plan_name, step_records but if the user provides any other field reject it.
How do I ensure this?
Thanks in advance

Related

Combining two choices in a single object

In my service schema I've got a single object that has two choices of properties. Meaning;
Object A needs: property 1 or 2, and property 3 or 4.
To realise this in OAS I'm using an object with an allOf property, which contains two items containing a oneOf property. I don't see a reason why this construction would be illegal. However, when using the swagger editor (https://editor.swagger.io/) and the Swagger Viewer extension in VSCode, it merges the two oneOf properties into a single one, effectively instructing the user to either include property 1, 2, 3 or 4.
One other way to achieve the same is to define a schema for every combination of choice 1 and 2, but this gets very tedious as the amount of options expands (effectively multiplying for every combination of the two choices).
Is my interpretation of the way this should work correct? If not, how can I achieve my goal without the spec becoming too verbose? If yes, I take it this is an issue in both tools I'm using, in that case I'll raise an issue in the respective issue trackers.
Example OAS spec:
openapi: 3.0.3
info:
description: Test API
version: 0.1.0
title: Test API
paths:
/test:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TestComplexObject'
responses:
'200':
description: OK
components:
schemas:
TestComplexObject:
type: object
allOf:
- type: object
properties:
defaultString:
type: string
- oneOf:
- $ref: '#/components/schemas/TestStr1'
- $ref: '#/components/schemas/TestStr2'
- oneOf:
- $ref: '#/components/schemas/TestStr3'
- $ref: '#/components/schemas/TestStr4'
TestStr1:
type: object
properties:
testString1:
type: string
required: [testString1]
TestStr2:
type: object
properties:
testString2:
type: string
required: [testString2]
TestStr3:
type: object
properties:
testString3:
type: string
required: [testString3]
TestStr4:
type: object
properties:
testString4:
type: string
required: [testString4]

Receiving error on json schema validation

I'm using the following schema to validate my json body payload however within api gateway I receive the error :
instance type (null) does not match any allowed primitive type (allowed:
["string"])]
Does anyone know what this means as I don't see how this relates to my schema?
schema:
components:
schemas:
submission:
type: object
required: [name, questions, metadata]
properties:
name:
type: string
questions:
$ref: '#/components/schemas/questions'
metadata:
type: object
required: [paymentSkipped]
properties:
paymentSkipped: bolean
additionalProperties: false
questions:
type: array
items:
$ref: '#/components/schemas/questionobj'
additionalProperties: false
questionobj:
type: object
required: [category, question]
properties:
category:
type: string
question:
type: string
The JSON literal null is recognized as a separate type in JSON Schema. If you want to allow strings and null, you need to include it in your type declaration:
{
"type": [ "string", "null" ]
...
}

OpenAPI 3: How to require one or more properties in PATCH requestBody?

I have a User resource:
I want to define a PATCH /users/{uid} so that the client can update image, bio or both.
An example valid request body would be:
{
"image": "filename.jpg",
"bio": "My biography"
}
If the image property is sent alone the existing bio property will remain the same on the server and only the image will be updated. If both are sent (as above) both will change.
In short:
an empty request body {} is disallowed.
{"image": "new.jpg"}, {"bio": "new bio" or {"image": "new.jpg", "bio": "new bio" is allowed.
This is what I have so far. I'm using the anyOf object with two separate type: objects within. I've tried this with Swagger hub using the virtserver, but the virtual server always seems to return 200 OK and passes back the example data regardless of whatever is passed, so I have no way to know.
Does my definition do what I intended? If not, what the best practice?
openapi: 3.0.0
...
patch:
summary: update a user
parameters:
- in: path
name: uid
description: user id
schema:
type: string
required: true
requestBody:
description: Update a user's profile
content:
application/json:
schema:
type: object
anyOf:
- type: object
properties:
image:
type: string
- type: object
properties:
bio:
type: string
additionalProperties: false
required: true
responses:
'200':
description: Successfully updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
You can use minProperties: 1:
requestBody:
description: Update a user's profile
content:
application/json:
schema:
type: object
properties:
image:
type: string
bio:
type: string
minProperties: 1 # <-----------
additionalProperties: false
or anyOf + required:
type: object
properties:
image:
type: string
bio:
type: string
anyOf: # <-----------
- required: [image]
- required: [bio]
additionalProperties: false
Your original example defines an empty object {} because:
Without required or minProperties defined, all properties are optional.
More importantly, additionalProperties: false only knows about the properties defined directly alongside it and has no visibility into subschemas. So, in this example it disallows ALL properties.
As for:
I've tried this with SwaggerHub using the VirtServer, but the virtual server always seems to return 200 OK and passes back the example data regardless of whatever is passed.
This is because SwaggerHub mocks do not validate inputs and always return a static response based on the response schema.
From SwaggerHub documentation:
Note that the mock does not support business logic, that is, it cannot send specific responses based on the input.
...
The mock generates static responses for each API operation based on its responses and the response media types defined in the spec.
If an operation has multiple response codes, the mock returns the response with the lowest status code. For example, if an operation has responses 201, 202 and 400, the mock returns the 201 response.

Define Kubernetes Custom Resource requiring one of the following fields or no fields

I try to define a new Custom Resource, requiring it to have one of (1) field A, (2) field B, or (3) empty body.
For example: {A: 1}, {B: 1}, {} are OK, but {A:1, B:2} is not.
Here is the definition of my Custom Resource in form of OpenApi schema:
foo:
type: object
properties:
a:
type: int
b:
type: int
oneOf:
- required: ["a"]
- required: ["b"]
# no sure how to include the empty body
How should I include the empty body in the oneOf constraint?
OpenAPI 3.1
You can use 'null' (with quotes).
oneOf:
- type: 'null'
Or an object with a property of type null.
oneOf:
- NullObjectExample:
type: object
properties:
prop1:
type: 'null'
OpenAPI 3.0
There is no null type, but you can use a nullable string. You may want to add a description stating this is expected to be null at all times.
oneOf:
- type: string
nullable: true
Or again, an object with a nullable string property.
oneOf:
- NullObjectExample:
type: object
properties:
prop1:
type: string
nullable: true
Why No Empty Object
In addition to not making intent clear, this presents a possible security vulnerability. See this page for an explanation. In short:
If you do not clearly define the schema and you leave properties of a JSON payload empty, you effectively allow attackers to pass in any data. This means that you are opening your backend to various attacks, such as SQL injection.

RAML 1.0 ciclical nested includes

I have this issue, I have created two libraries to define two different types, here they are:
Category.raml
#%RAML 1.0 Library
uses:
- Event: !include Event.raml
- Tournament: !include Tournament.raml
types:
#############################################################################
base:
usage: The base type for a category
properties:
min_age:
description: The minimum age to participate in the category
required: true
type: number
max_age:
description: The maximum age to participate in the category
required: true
type: number
name:
description: The name of the category
required: true
type: string
gender:
description: The gender of the category
required: true
enum:
- male
- female
- mix
tournament:
description: The tournament of the category
required: true
type: Tournament.base
#############################################################################
full:
usage: A category with all of its events
type: base
properties:
events:
description: The events that the category contains
required: true
type: Event.base[]
Tournament.raml
#%RAML 1.0 Library
uses:
- ClubInscription: !include Club.raml
- Category: !include Category.raml
types:
#############################################################################
base:
usage: The base type for the tournament
properties:
name:
description: The name of the tournament
required: true
type: string
date:
description: Date of the tournament
required: true
type: string
available_lanes:
description: Maximum number of lanes in a serie
required: true
type: number
max_swimmer_inscriptions:
description: Maximum number of events a swimmer may be inscripted
required: true
type: number
award_type:
description: The type of awarding used in the competition
required: true
enum:
- points
- medals
- none
state:
description: The current state of the tournament
required: true
enum:
- closed
- open
- finished
#############################################################################
full:
usage: A tournament with all its categories and club inscriptions
type: base
properties:
club_inscriptions:
description: The clubs inscripted in the tournament
required: true
type: ClubInscription.base[]
categories:
description: The categories the tournament has
required: true
type: Category.base[]
Having this, it makes sense having a conflict. I am pretty knew at RAML, so I read somewhere that "uses" should only be used when using something as a parent, but then what should I do to not re-write everything in everywhere in my project (because this happens everywhere in it).
I have thought of defining the base of the types in one file, but it would be just a mix of information that should not be together, I want to know if there is an alternative to "uses" to re-use the types in another file.
Thanks in advance.
The simplest solution is make:
TournamentBase.raml
TournamentFull.raml
CategoryBase.raml
CategoryFull.raml
You will not have circular dependencies.