Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request body is required but all properties are optional #247

Open
bigludo7 opened this issue Jul 10, 2024 · 16 comments · May be fixed by #358
Open

Request body is required but all properties are optional #247

bigludo7 opened this issue Jul 10, 2024 · 16 comments · May be fixed by #358
Labels
documentation Improvements or additions to documentation

Comments

@bigludo7
Copy link
Collaborator

Problem description
A small one but need global alignement in all our API.
This one was raised by @fernandopradocabrillo in SIM Swap API and we got the same question with @FabrizioMoggio in Call Forwarding API.

The request body is required for an api, but all attributes are optional. What should be the body when the client doesn't need to send any attributes?

We have 2 options:

  1. Leave it as required and force the client to send an empty body -> {}
  2. Remove the requirement (required=true for the requestBody) and let the client send a POST without body

Expected action
Define the behaviour when the client doen't need to send any request body param. It could a sentence in the design guideline.
As of now with @fernandopradocabrillo we have a preference for option 1 in sim-swap.

Additional context
It is important to define this behavior to include the scenarios in the test plan.

@bigludo7 bigludo7 added the documentation Improvements or additions to documentation label Jul 10, 2024
@uwerauschenbach
Copy link
Collaborator

uwerauschenbach commented Jul 11, 2024 via email

@FabrizioMoggio
Copy link
Collaborator

In the Call Forwarding Signal API we are adopting option 1

@PedroDiez
Copy link
Collaborator

We also prefer option 1

@eric-murray
Copy link
Collaborator

In Device Identifier, we had a subtly different problem because the request body is the Device object, and so the optional fields of the body are the fields of the Device object. Because of the minProperties: 1 directive, this means an empty body is not a valid option. Hence the only option for the API consumer if they don't want to send a device subscription parameter (because they are using a 3-legged token) is not to send any body at all.

I decided this was a better solution because it saves on a couple of request headers (Content-Length and Content-Type if I remember correctly), and so should be more efficient. And this will be the normal way of calling this API, given that the Device object contains PII, and so 3-legged tokens should be used.

I'm happy to revisit this decision if there are good arguments in favour of empty body over no body, but otherwise any text that goes into the design guidelines has to be careful not to effectively mandate that POST requests always have a body, even if empty.

@bigludo7
Copy link
Collaborator Author

bigludo7 commented Jul 18, 2024

I think @eric-murray you trigger another point about inconsistency in our pattern.

In device identifier and in device status (for device-roaming-status for example) we have only the device structure in request but not same model.

Device identifier:

  "phoneNumber": "123456789",
  "networkAccessIdentifier": "[email protected]",
  "ipv4Address": {
    "publicAddress": "84.125.93.10",
    "publicPort": 59765
  },
  "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
}

device-roaming-status:

  "device": {
    "phoneNumber": "+123456789",
    "networkAccessIdentifier": "[email protected]",
    "ipv4Address": {
      "publicAddress": "84.125.93.10",
      "publicPort": 59765
    },
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  }
}

Both implement Device as specified - probably we need to align?

@uwerauschenbach
Copy link
Collaborator

uwerauschenbach commented Jul 19, 2024 via email

@eric-murray
Copy link
Collaborator

@uwerauschenbach
An empty body requires a Content-Length : 0 header, whereas no body at all requires no Content-Length header. Indeed, it is the presence of the Content-Length : 0 header that defines the request has a body (albeit empty). Nothing else is sent as the empty body itself.

Try wiresharking the following commands and tell me what you see:

curl -X POST http://localhost       # No body
curl --data "" http://localhost     # Empty body

@uwerauschenbach
Copy link
Collaborator

uwerauschenbach commented Jul 22, 2024 via email

@eric-murray
Copy link
Collaborator

@uwerauschenbach @bigludo7

So I think the better pattern for "future-proofness" is that of device-roaming-status, as the current device-identifier definition cannot be extended with additional optional attributes without introducing breaking changes (i.e. introducing an explicit device field as well). However, it is more likely that device-identifier will drop identifiers other than phoneNumber (like sim-swap) as this is the major use case, and I think it cleaner to have:

{ "phoneNumber": "+123456789" }

rather than:

{ device: {"phoneNumber": "+123456789" }}

Currently sim-swap is required to pass a phoneNumber, but I guess that will be changed and they will have the same discussion as to whether to pass an empty JSON object or no body at all. My preference remains no body at all as this gives a minor performance advantage, but I agree this is a marginal consideration. My tests suggest sending no body saves 53 bytes over sending an empty JSON object.

So I am happy for Commonalties to align on a pattern for passing the Device object, but device-identifier may not use this object in future.

Also, I realise that your option 1 is actually "empty JSON object" (i.e. {}) rather than "empty body". An empty body itself is not a valid JSON object.

@uwerauschenbach
Copy link
Collaborator

uwerauschenbach commented Jul 22, 2024 via email

@eric-murray
Copy link
Collaborator

@bigludo7 @uwerauschenbach @PedroDiez @PedroDiez
For Device Identifier, I'm now proposing that that API adopts the same pattern as other APIs (i.e. mandatory body with optional Device object named device). See PR #87.

So we should update the design guidelines, making this pattern a requirement for APIs that allow passing of an optional device or phoneNumber parameter, even if it is the only parameter.

@bigludo7
Copy link
Collaborator Author

bigludo7 commented Dec 6, 2024

@bigludo7 @uwerauschenbach @PedroDiez @PedroDiez For Device Identifier, I'm now proposing that that API adopts the same pattern as other APIs (i.e. mandatory body with optional Device object named device). See PR #87.

So we should update the design guidelines, making this pattern a requirement for APIs that allow passing of an optional device or phoneNumber parameter, even if it is the only parameter.

Fully aligned for Device identifier @eric-murray as we have all possible identifiers

For the generic rule you mean that for simswap for example we should move from:

{
  "phoneNumber": "+346661113334",
  "maxAge": 240
}

to:

{
  "device": {
         "phoneNumber": "+346661113334"
         },
  "maxAge": 240
}

With only phoneNumber as identifier possible within device.

I'm not against the idea but not very elegant no?

@eric-murray
Copy link
Collaborator

For the generic rule you mean that for simswap for example we should move from:

{
  "phoneNumber": "+346661113334",
  "maxAge": 240
}

to:

{
  "device": {
         "phoneNumber": "+346661113334"
         },
  "maxAge": 240
}

With only phoneNumber as identifier possible within device.

I'm not against the idea but not very elegant no?

No, not that. I meant that having the request body optional when the only parameter allowed is phoneNumber would not be allowed either.

So the following would NOT be allowed:

      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/JSONSchemaThatOnlyContainsPhoneNumber"

I suppose you could generalise the rule to say that all POST requests MUST have a body, even if that is an empty JSON.

@eric-murray
Copy link
Collaborator

@bigludo7 @uwerauschenbach @PedroDiez

Any views on "codifying" this with the following change to Section 3.1 of the design guidelines:

From:

When the POST method is used, the resource in the path must be a verb (e.g. retrieve-location and not location) to differentiate from an actual resource creation.

To:

When the POST method is used:

  • the resource in the path MUST be a verb (e.g. retrieve-location and not location) to differentiate from an actual resource creation
  • the request body itself MUST be a JSON object and MUST be required, even if all properties are optional

Because the Device object must have at least one property, this wording prevents the request body being defined as the Device object itself (because then there would be no way to specify no device identifiers).

For the phone number only flavour of APIs, an API that only has phoneNumber as a possible input would also require to use an empty JSON when that was omitted.

As far as I can tell, this would not be a breaking change for any API (now that Device Identifier is making the request body required). KYC fill-in does not define a POST body at all, but I guess that is because they do not want 2-legged token support, so they would not need to add one.

@bigludo7
Copy link
Collaborator Author

Hello @eric-murray
Work for me with your proposal.

@eric-murray eric-murray linked a pull request Dec 16, 2024 that will close this issue
2 tasks
@PedroDiez
Copy link
Collaborator

Hello @eric-murray,
Ok, with your proposal as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants