Parameters cannot have both a "in: body" and "in: formData", as "formData" _will_ be the body

I’m using 5.1.0 to generate our API. A customer has tried to import the resulting openapi.json file into Swagger Editor and has come up with a bunch of validation errors. I’ve seen similar topics in the forum but they all seem to suggest the issue was fixed in 4.9.x.

My DTO is:

[DataContract]
[Route(“/candidate”, “PUT”, Summary = “Create or update a candidate”)]
public class CandidatePut : IReturn, IProfilePutRequest
{
// Unique to this put
[DataMember]
[ApiMember(Description = “Details of the candidate to update or add”, IsRequired = true)]
[ServiceField(Required = true)]
public Candidate candidate { get; set; }
}

and the Swagger Editor shows:

put:
tags:
- candidate
summary: Create or update a candidate
description: Create or update a candidate
operationId: CandidatePut_Create
consumes:
- application/x-www-form-urlencoded
produces:
- application/json
parameters:
- name: candidate
in: formData
schema:
$ref: ‘#/definitions/Candidate’
description: Details of the candidate to update or add
required: true
- name: body
in: body
schema:
$ref: ‘#/definitions/CandidatePut’
responses:
‘200’:
description: Success
schema:
$ref: ‘#/definitions/CandidatePutResponse’
deprecated: false
parameters:
- $ref: ‘#/parameters/Accept’

and errors of:

Semantic error at paths./candidate.put.parameters
Parameters cannot have both a “in: body” and “in: formData”, as “formData” will be the body
Jump to line 114
Schema error at paths[‘/candidate’].put.parameters[0]
should NOT have additional properties
additionalProperty: schema, name, in, description, required
Jump to line 114
Schema error at paths[‘/candidate’].put.parameters[0].in
should be equal to one of the allowed values
allowedValues: body, header, query, path
Jump to line 115

Any ideas or hints on what I am missing to generate a valid schema.

TIA

Nic

Are you using the newer OpenApiFeature? if not you should switch to that instead, if you are please include the full steps to view the validation errors including all missing DTOs like Candidate that is required to repro the issue.

I am using the latest OpenAPI feature. I’ve been able to produce a simple sample using the latest nugget packages that shows the error. Basically compile and run, then open the openapi.json in Swagger Editor to see the schema errors.

Unfortunately I can’t figure out or find any help on how to upload the sample.

Just upload the project on GitHub and post the link here. What Swagger Editor are you referring to? The /swagger-ui/ or something else?

Ah OK, I thought you might have some special process to upload projects. Unfortunately I can’t access GitHub so the project is here on onedrive - hopefully you can access it. The tool my client has been trying to use and therefore the tool I am trying to test with is (Swagger Editor - you can load a file or from a URL via the “File” option at the top of the screen.

Once the file or URL has been processed you should be able to see all the validation errors in the right hand panel:

The issue is ServiceStack supports multiple ways of calling your Service whereas the Swagger Editor is stricter than the Swagger UI and only wants one way to be specified.

You can disable generating the body input option with:

Plugins.Add(new OpenApiFeature { DisableAutoDtoInBodyParam = true });

Then it will only generate the formData input option, the problem then becomes Swagger Editor doesn’t allow submitting Complex Types via formData even though ServiceStack supports it so you couldn’t have a complex type property like Candidate:

public class CandidatePut : IReturn<CandidatePutResponse>
{
    public Candidate candidate { get; set; }
}

You would instead need to keep Request DTOs flat so they only contain (non complex) scalar types, in this case moving all properties of Candidate to your Request DTO, e.g:

public class CandidatePut : IReturn<CandidatePutResponse>
{
    public Int32 CandidateRef { get; set; }
}

This does make your Services more interoperable as most external clients don’t support it and there’s not an official standard for populating Complex Type via queryString or formData.

If you go this route then you could easily populate the Candidate DTO from the Request DTO using the built-in Auto Mapping Utils, e.g:

public class CandidateService : Service
{
    public object Any(CandidatePut request)
    {
        var candidate = request.ConvertTo<Candidate>();
    }
}

@nic65535

If you don’t need the FormData support documented in the OpenApi doc then you can decorate the service params with [ApiMember(ParameterType = "model")] so it will be body only eg:

public class CandidatePut : IReturn<CandidatePutResponse>
{
    [ApiMember(ParameterType = "model")]
    public Candidate candidate { get; set; }
}

More info in this post: https://forums.servicestack.net/t/opposite-of-disableautodtoinbodyparam/

1 Like

Thanks George that does seem to solve a lot of my errors.

My one remaining issue is with the following in the DTO:

    [DataMember]
    [ApiMember(Description = "Fields within a row", IsRequired = true)]
    public List<KeyValuePair<string, string>> Fields { get; set; }

Which ends up as

   $ref: '#/definitions/KeyValuePair<String,String>'

in the generated openapi.json. From the error I would guess that the <> are not allowed:

Semantic error at definitions.Row.properties.Fields.items.$ref
$ref values must be RFC3986-compliant percent-encoded URIs

Any idea if or how I can fix this?

TIA

Nic

You can use a POCO like Property instead of a generic KeyValuePair struct.

Thanks - that helps me fix my types but I have found that if a response DTO contains only the ServiceStack ResponseStatus:

public class CandidateDeleteResponse : IHasResponseStatus
{
    public ResponseStatus ResponseStatus { get; set; }
}

then the resultant output still has an error:

Semantic error at definitions.ResponseStatus.properties.Meta.$ref
$ref values must be RFC3986-compliant percent-encoded URIs

ResponseStatus:
title: ResponseStatus
properties:
ErrorCode:
type: string
Message:
type: string
StackTrace:
type: string
Errors:
type: array
items:
$ref: ‘#/definitions/ResponseError’
Meta:
$ref: ‘#/definitions/Dictionary<String,String>’
description: ResponseStatus
type: object

Oddly this doesn’t happen if the response DTO has another parameter in it. Happy to upload another sample if that makes it clearer.

Thanks again

Nic

Sorry can’t get that error to paste with the <> brackets for some reason.
Basically the $ref line should read

$ref: '#/definitions/Dictionary<String,String>'

Seems Swagger 3 has added a number of new restrictions on existing values, this commit should resolve this error.

This change is available from v5.4.1 that’s now available on MyGet.

1 Like

Perfect - that fixes that.

Great support yet again from ServiceStack.