StepZen is now part of IBM. For the most recent product information and updates go to
https://www.ibm.com/products/stepzen

Encode Content-Type Form Data

Referencing Content-Types in GraphQL schemas to POST form data.

An HTTP request such as PATCH, POST and PUT can include data that is to be sent as part of that request. This is accomplished by including a Content-Type header that specifies the media (data) type being sent in an HTTP request. StepZen supports two of the most common content types for encoding form data:

  • application/x-www-form-urlencoded
  • application/json

This topic provides the following information about encoding data into requests:

How Form Data is Encoded into a Request

Data can be appended in many different ways and it must be computer-readable with URL-encoded formatting. StepZen's Encoding Form Data feature eliminates many of the difficulties and automates issues found in form data syntax for the developer.

Depending on the type of content being sent in an HTTP POST method, there are explicit ways the resources must be sent to be successful.

Content-Type: application/x-www-form-urlencoded requests the data to be one long query string appended to the URL:

https://api.example.com/oauth/v1/token?grant_type=refresh_token&client_id=$client_id&client_secret=$client_secret&refresh_token=$refresh_token

Content-Type: application/json requests the data to be sent as a JSON object in the body of the request:

{
  "grant_type": "string",
  "client_id": "string",
  "client_secret": "string",
  "refresh_token": "string"
}

How to Encode Form Data on an HTTP POST Method in StepZen

StepZen's @rest directive supports the HTTP POST method and header parameters in a GraphQL schema to generate the encoded form data.

In the Cloudmersive example below, the GraphQL query compares the similarity of two strings and returns a similarity score:

"""
Perform Semantic Similarity Comparison of Two Strings
Analyze two input text strings, typically sentences, and determine the semantic similarity of each.  Semantic similarity refers to the degree to which two sentences mean the same thing semantically.
"""
cloudmersive_Analytics_Similarity(
    """
    Authorization with APIKey
    """
    cloudmersive_apiKey: Secret!
    TextToAnalyze1: String
    TextToAnalyze2: String
  ): Cloudmersive_SimilarityAnalysisResponse
    @rest(
      endpoint: "https://testapi.cloudmersive.com/nlp-v2/analytics/similarity"
      method: POST
      postbody: ""
      contenttype: "application/json"
      headers: [{ name: "ApiKey", value: "$cloudmersive_apiKey" }]
    )

Content-Type: application/json

The configuration properties are essential to properly execute the StepZen @rest directive.

  • endpoint: The REST endpoint that will be used to populate the query result.
  • method: The action the request is making to the REST endpoint.
  • headers: Custom HTTP headers to pass e.g. cookies and authentication tokens.
  • contenttype: Specifies the media type the request is sending to the REST endpoint.
  • postbody: The resource data being sent in the body of the request.

Breaking down the Cloudmersive query example, there are three GraphQL arguments:

cloudmersive_apiKey: Secret!
TextToAnalyze1: String
TextToAnalyze2: String

These arguments will be used as variables in the @rest request, and the cloudmersive_apiKey is explicitly declared in the headers configuration property with the $:

headers: [{ name: "ApiKey", value: "$cloudmersive_apiKey" }]

Where do we inject the TextToAnalyze variables in the @rest request? This is where the encoded form data feature comes into action.

The configuration properties below tell StepZen that this method can encode the form data:

method: POST
contenttype: "application/json"
postbody: ""

Notice Content-Type is application/json and postbody is empty, so StepZen recognizes these configurations and injects the undeclared variables into the body of the request. cloudmersive_apiKey is declared in the header configuration, so it is left out of the body:

{
  "TextToAnalyze1": "string",
  "TextToAnalyze2": "string"
}

Query

Running the query below, will send the proper request to the endpoint https://testapi.cloudmersive.com/nlp-v2/analytics/similarity and receive a response with the similarity score:

query MyQuery($cloudmersive_apiKey: Secret = "") {
  cloudmersive_Analytics_Similarity(
    cloudmersive_apiKey: $cloudmersive_apiKey
    TextToAnalyze1: "running around the block"
    TextToAnalyze2: "running around the corner"
  ) {
    SentenceCount
    SimilarityScoreResult
    Successful
  }
}

Query result

{
  "data": {
    "cloudmersive_Analytics_Similarity": {
      "SentenceCount": 2,
      "SimilarityScoreResult": 0.0019565322436392307,
      "Successful": true
    }
  }
}

Content-Type: application/x-www-form-urlencoded

Using the same example cloudmersive_Analytics_Similarity, if the endpoint https://testapi.cloudmersive.com/nlp-v2/analytics/similarity now wanted application/x-www-form-urlencoded as the Content-Type, the only change that is needed in the schema is the contenttype configuration.

The existing configuration:

contenttype: "application/json"

Changes to this configuration:

contenttype: "application/x-www-form-urlencoded"

That is it. The configuration change will be recognized, and now instead of creating a body property, the undeclared variables will be appended to the URL as a long urlencoded string!

https://testapi.cloudmersive.com/nlp-v2/analytics/similarity?TextToAnalyze1=running%20around%20the%20block&TextToAnalyze2=running%20around%20the%20corner

Renaming

If you need to change the field names in the automatically generated bodies, you can do that using the arguments attribute for the directive. In the example below we have changed the names from camelCase to snake_case:

type Mutation {
  updateUserRename(firstName: String lastName: String): JSON
    @rest(
      endpoint: "https://httpbin.org/patch"
      method: PATCH
      arguments: [
        {argument:"firstName", name:"first_name"},
        {argument:"lastName", name:"last_name"}
      ]
    )
}

Running the query:

mutation stepzenPatch {
  updateUserRename(firstName: "John")
}

Would result in the following JSON being sent as the body:

{
  "first_name": "John"
}

Optional values

autopostbody will ignore nullable arguments. In the renaming example above, you can see that only first_name was included, because lastName was null.

Important Caveats

  • Using other Content-Types will not encode the data.
  • postbody is an optional argument for this feature. It does not need to be included to encode the data. The examples above include postbody to show how the body of an HTTP method is included in the @rest directive for encoding form data.
  • PATCH using auto postbody may work for your application using nullable to elide values; however, if you use JSONPatch, you'll want to use postbody.