Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Kinga
Kinga

Posted on • Edited on

     

APIM JSON Schema Validation done easy

For way too long we had to use transformation policy (<set-body>,throw new Exception,<on-error>) to validate JSON schema.

No more =)
We finally havecontent validation policies:

The policy validates the following content in the request or response against the schema:

  • Presence of all required properties.
  • Absence of additional properties, if the schema has the additionalProperties field set to false.
  • Types of all properties. For example, if a schema specifies a property as an integer, the request (or response) must include an integer and not another type, such as a string.
  • The format of the properties, if specified in the schema - for example, regex (if the pattern keyword is specified), minimum for integers, and so on.

And by "finally" I mean, since a few months now. But I don't see many posts about it, so here we are =)

Let's assume I already have anAPIM bicep template that provisions API Management Instance.

I will now extend my Bicep template with schema to be used in validation, and in definitions.

Defining JSON schema

First things first. Below is my schema and payload example.

main.bicep

var schemaExampleUser1 = 'john.doe@${tenantName}.onmicrosoft.com'var schemaPersonRequired = [  'firstName'  'lastName']var schemaPerson = {  firstName: {    type: 'string'  }  lastName: {    type: 'string'  }  age: {    type: 'integer'    minimum: 0  }  email: {    type: 'string'    format: 'email'    pattern: '^\\S+@\\S+\\.\\S+$'  }}var personExample = {  firstName: 'John'  lastName: 'Doe'  age: 25  email: schemaExampleUser1}
Enter fullscreen modeExit fullscreen mode

API Management resources

Policies

I have a number of policies that I want to mix-and-match depending on the API. To keep things neat, I keep them in separate variables, and compose a final definition as needed.

main.bicep

var authorizationPolicy = '''        <!-- Service Bus Authorization-->        <authentication-managed-identity resource="https://servicebus.azure.net/" output-token-variable-name="msi-access-token" ignore-error="false" />        <set-header name="Authorization" exists-action="override">            <value>@("Bearer " + (string)context.Variables["msi-access-token"])</value>        </set-header>        <set-header name="Content-Type" exists-action="override">            <value>application/atom+xml;type=entry;charset=utf-8</value>        </set-header>        <set-header name="BrokerProperties" exists-action="override">            <value>{}</value>        </set-header>'''var mockResponse = '<mock-response status-code="200" content-type="application/json" />'var validatePersonPolicy = '''        <validate-content unspecified-content-type-action="detect" max-size="102400" size-exceeded-action="prevent" errors-variable-name="validationErrors">          <content type="application/json" validate-as="json" action="prevent" schema-id="Person" />        </validate-content>'''var policySchema = '''  <!--ADD {0}-->  <policies>      <inbound>        <base />        <!-- Validation -->        {1}        <!-- Authorization -->        {2}        <!-- Mock response -->        {3}      </inbound>      <backend>        <base />      </backend>      <outbound>        <base />      </outbound>      <on-error>        <base />      </on-error>    </policies>'''var personPolicy = format(policySchema, 'PORTFOLIO', validatePersonPolicy, authorizationPolicy, '<!-- N/A -->')
Enter fullscreen modeExit fullscreen mode

Schema

Now it's time to createschema definition in the already existing API Management instance.

main.bicep

resource apiManagement 'Microsoft.ApiManagement/service@2021-08-01' existing = {  name: serviceName}resource apiManagement_schemaPerson 'Microsoft.ApiManagement/service/schemas@2021-08-01' = {  name: 'Person'  parent: apiManagement  properties: {    schemaType: 'json'    description: 'Schema for a Person Object'    document: any({      type: 'array'      items: {        type: 'object'        properties: schemaPerson        required: schemaPersonRequired      }    })  }}
Enter fullscreen modeExit fullscreen mode

After deployment, you will find it underAPIs/Schemas:
Image description

API

Next step is to create an API, definition, and an operation. I'm referencing the schema and the example created in the first step.
In this example, theAdd Person operation saves the payload to a ServiceBus queue, that's why theurlTemplate is set to/${serviceBusQueueName1}/messages.
I'm mentioning it just to point out you have to remember about the "messages" at the end of the url ;)

main.bicep

resource apiManagement_apiName 'Microsoft.ApiManagement/service/apis@2021-08-01' = {  name: '${serviceName}/${apiName}'  properties: {    displayName: apiDisplayName    subscriptionRequired: true    path: 'person-schema-validation'    protocols: [      'https'    ]    isCurrent: true    description: 'Personal data ingestion'    subscriptionKeyParameterNames: {      header: 'Subscription-Key-Header-Name'      query: 'subscription-key-query-param-name'    }  }}resource apiManagement_apiName_apiSchemaGuid 'Microsoft.ApiManagement/service/apis/schemas@2021-08-01' = {  parent: apiManagement_apiName  name: apiSchemaGuid  properties: {    contentType: 'application/vnd.oai.openapi.components+json'    document: any({      components: {        schemas: {          Definition_Person: {            type: 'object'            properties: schemaPerson            required: schemaPersonRequired            example: personExample          }        }      }    })  }}resource apiManagement_apiName_operation_addPerson 'Microsoft.ApiManagement/service/apis/operations@2021-08-01' = {  parent: apiManagement_apiName  name: operation_addPerson  dependsOn: [    apiManagement_apiName_apiSchemaGuid  ]  properties: {    request: {      headers: [        {          name: 'Content-Type'          type: 'string'          required: true          values: [            'application/json'          ]        }      ]      representations: [        {          contentType: 'application/json'          schemaId: apiSchemaGuid          typeName: 'Definition_Person'        }      ]    }    displayName: 'Add Person'    description: 'Add Person Information to ServiceBus. \nThe Request Body is parsed to ensure correct schema.'    method: 'POST'    urlTemplate: '/${serviceBusQueueName1}/messages'  }}
Enter fullscreen modeExit fullscreen mode

Schema Validation

And now, that I have everything in place, I can use schema validation. Finally!

The first policy is actually not a validation. It is applied to all the operations, and it ensures that the backend url is set to the ServiceBus Endpoint.

The second policy ensures that the payload receives passes schema validation.

main.bicep

resource serviceName_apiName_policy 'Microsoft.ApiManagement/service/apis/policies@2021-08-01' = {  parent: apiManagement_apiName  name: 'policy'  properties: {    value: '<!-- All operations-->\r\n<policies>\r\n  <inbound>\r\n    <base/>\r\n    <set-backend-service base-url="${serviceBusEndpoint}" />\r\n  <set-header name="Content-Type" exists-action="override">\r\n  <value>application/json</value>\r\n  </set-header>\r\n  </inbound>\r\n  <backend>\r\n    <base />\r\n  </backend>\r\n  <outbound>\r\n    <base />\r\n  </outbound>\r\n  <on-error>\r\n    <base />\r\n  </on-error>\r\n</policies>'    format: 'rawxml'  }}resource apiManagement_apiName_operation_addPerson_policy 'Microsoft.ApiManagement/service/apis/operations/policies@2021-08-01' = {  parent: apiManagement_apiName_operation_addPerson  name: 'policy'  properties: {    value: personPolicy    format: 'rawxml'  }}
Enter fullscreen modeExit fullscreen mode

Image description

The bicep template is onGitHub.

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
mattfrear profile image
Matt Frear
  • Joined

Your validate-content defines schema-id="Portfolio" but I can't see "Portfolio" defined anywhere else, so this doesn't seem correct?

CollapseExpand
 
kkazala profile image
Kinga
„Simplicity is the ultimate sophistication”- Leonardo da Vinci
  • Location
    Zürich
  • Work
    M365 and Azure Solutions Architect
  • Joined

thank you@mattfrear for letting me know. 🙏 It should indeed be "Person" and not "Portfolio".
I have another schema used productively and I missed the schema-id parameter when preparing the sample

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

„Simplicity is the ultimate sophistication”- Leonardo da Vinci
  • Location
    Zürich
  • Work
    M365 and Azure Solutions Architect
  • Joined

More fromKinga

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp