ServiceStack - extending AutoQuery Metadata with - servicestack

Using the SwaggerFeature plugin in ServiceStack, I can annotate the properties of a DTO using the ApiMember attribute.
Example:
[Route("/swagger/{Name}", "POST"]
public class MyRequestDto
{
[ApiMember(Name="Name", Description = "Name Description",
ParameterType = "path", DataType = "string", IsRequired = true)]
public string Name { get; set; }
}
Is it possible to include these additional annotations for properties in the AutoQuery metadata service?

The schema for AutoQuery Metadata doesn't allow for this metadata which would change the scope and purpose of the AutoQuery Metadata.
This information is also redundant as this metadata about Services is maintained in the /types/metadata route which returns the MetadataTypes DTO.

Related

ServiceStack Open API - Swagger UI not displaying enum values as dropdown

I have recently upgraded my ServiceStack libraries from 5.10.4 to 6.5.0 and implemented Open API as specified in the documentation. But my Enum properties are displayed as Textbox instead of Dropdown in the /swagger-ui page.
This was working as expected previously when I was using 'ServiceStack.Api.Swagger' instead of 'ServiceStack.Api.OpenApi'.
Can someone please help me in this?
Thanks and Regards,
Sibin
Below are the code I am using:
// Configuration
Plugins.Add(new OpenApiFeature());
// DTO
[Route("my-route", "GET", Summary = "My summary")]
public class MyClass: IReturn<MyResponse>
{
[ApiMember(Name = "Alphabet", Description = "Alphabet",
ParameterType = "path", DataType = "string", IsRequired = true)]
[ApiAllowableValues("Alphabet", typeof(Alphabets))]
public string Alphabet { get; set; }
}
// Enum
public enum Alphabets
{
A,
B,
C,
D
}
This should now be resolved in the latest v6.5.1+ that's now available on MyGet.
Alternatively you can change your DTO to have an Enum property, which also doesn't require an [ApiAllowableValues] attribute, e.g:
[Route("/my-route", "GET", Summary = "My summary")]
public class MyClass: IReturn<MyResponse>
{
[ApiMember(Name = "Alphabet", Description = "Alphabet",
ParameterType = "path", DataType = "string", IsRequired = true)]
public Alphabets Alphabet { get; set; }
}
If you haven't already, checkout API Explorer that's built into ServiceStack v6+ which you can view from /ui or a specific API from /ui/{RequestDto} e.g. /ui/MyClass.

Change Autoquery return type in DTO generation

I want to return a custom class from my custom AutoQuery endpoint that inherits QueryResponse<T> but adds a few extra properties.
public class WritingAssignmentBlogLookUpResponse : QueryResponse<BlogDto>, IResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public string DebugMessage { get; set; }
}
But if I specify request like so:
[Route("/assignment/blogs/", "POST")]
public class WritingAssignmentBlogsLookUpRequest : QueryDb<Blog, BlogDto>, IReturn<WritingAssignmentBlogLookUpResponse>
{
}
Then the return type specified in generatd DTO for client.post(req) is QueryResponse<BlogDto> and it doesn't generate WritingAssignmentBlogLookUpResponse at all.
Do I just have to specify return type as any from my typescript service or is there a way to make the types match so I can strongly type it?
You can’t change AutoQuery responses which are already fixed in their service contract definition to return a QueryResponse<T>.
You can add extra info to the Meta Dictionary of the Response DTO (exists for this reason) otherwise if you need to change the Service Contract you’d need to convert it into a normal (I.e. non-AutoQuery) API which could use the Service Gateway to call an existing AutoQuery API that decorates the response.

Defining OpenApi response schemas - particularly the example field - with ServiceStack.Api.OpenApi

When I generate an API spec on SwaggerHub, I can declare the schemas, including user-friendly examples, as follows:
components:
schemas:
Job:
type: object
required:
- position
- department
- startDate
properties:
jobId:
type: integer
format: int32
position:
type: string
example: Copy Boy III
department:
type: string
example: Legal
startDate:
type: string
format: date
example: '2019-10-01'
I can't figure out how to generate the same using the attributes in ServiceStack OpenAPI. Do I put attributes on my Response DTO? Or on my type? I can't find any attribute that seems to correspond to the "example" field.
I've tried using [ApiMember], which looks like the closest possible option, on both the Response DTO and the type the response is tied to, but neither seems to make a difference. Here are a few things I've tried, just in the hopes of seeing a change in the Swagger UI, but neither has worked:
// In the DTO
public class JobResponse
{
[ApiMember(Name = "Job", DataType = "array")] // Will this do anything?
public Job Job { get; set; }
public ResponseStatus ResponseStatus { get; set; } // inject structured errors
}
// In the Type
public class Job : IEntity
{
[Required][DataMember(Name = "jobId")]
public int Id { get; set; }
[ServiceStack.ApiMember(Name = "test", DataType = "string", IsRequired = true)] // Will this do anything?
public string Position { get; set; }
public string Department { get; set; }
public DateTime? StartDate { get; set; }
}
You'd typically use Open API Attributes in order to customize the metadata returned in the generated /openapi specification of your Services.
Attributes to describe the Operation should be on the Request DTO, here's an example of an annotated Request DTO:
[Api("Service Description")]
[Tag("Core Requests")]
[ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")]
[ApiResponse(HttpStatusCode.InternalServerError, "Oops, something broke")]
[Route("/swagger/{Name}", "GET", Summary = "GET Summary", Notes = "Notes")]
[Route("/swagger/{Name}", "POST", Summary = "POST Summary", Notes="Notes")]
public class MyRequestDto
{
[ApiMember(Name="Name", Description = "Name Description",
ParameterType = "path", DataType = "string", IsRequired = true)]
[ApiAllowableValues("Name", typeof(Color))] //Enum
public string Name { get; set; }
}
You can also use [ApiMember] on normal DTO Type properties if you want to override their default representation.
Whenever you need more fine-grained control over the generated /openapi you can use Operation Filters on the OpenApiFeature plugin, e.g:
Plugins.Add(new OpenApiFeature
{
OperationFilter = (verb, operation) => operation.Tags.Add("all operations")
});
Available configuration options:
ApiDeclarationFilter - allows to modify final result of returned OpenAPI json
OperationFilter - allows to modify operations
SchemaFilter - allows to modify OpenAPI schema for user types
SchemaPropertyFilter - allows to modify propery declarations in
OpenAPI schema

Swagger UI and ServiceStack

Does Service Stack support Models in Swagger.
In the sample code below
[Route("/User", "GET", Summary = "Get all the users available")]
[Route("/User", "POST, PUT", Summary = "Create a new user")]
[Route("/User/{Id}", "GET", Summary = "Get user with a specific id")]
public class User : RequestBase, IReturn<UserResponse>
{
[ApiMember(Name = "Id", Description = "The User Id", ParameterType = "path", DataType = "int", IsRequired = false)]
public int Id { get; set; }
[ApiMember(Name = "UserData", Description = "The User Data", ParameterType = "body", DataType = "complex", IsRequired = false)]
public UserData Entry { get; set; }
}
I would like UserData to be a complex type or container type. However if I define it to be one of these, all I get in the SwaggerUI is a text area box. I do not get the Model and ModelSchema links that I see in the petstore example online.
http://petstore.swagger.wordnik.com/#!/pet/addPet_post_1
Parameters of type "body" are properly supported as of the latest ServiceStack releases. You will need to set DataType = "User" in your second ApiMember attribute. This will allow the Swagger UI to correctly display model schema information. Also, for simple types, you can use constants in the SwaggerType class; for example you can change the first Apimember attribute to have DataType = SwaggerType.Int.

Do Azure table services entities have an equivalent of NonSerializedAttribute?

If I'm trying to serialize a normal CLR object, and I do not want a particular member variable to be serialized, I can tag it with the
[NonSerialized]
attribute. If I am creating a table services entity, is there an equivalent attribute I can use to tell Azure table services to ignore this property?
For Version 2.1 there is a new Microsoft.WindowsAzure.Storage.Table.IgnoreProperty attribute. See the 2.1 release notes for more information: http://blogs.msdn.com/b/windowsazurestorage/archive/2013/09/07/announcing-storage-client-library-2-1-rtm.aspx.
There's no equivalent I know of.
This post says how you can achieve the desired effect - http://blogs.msdn.com/b/phaniraj/archive/2008/12/11/customizing-serialization-of-entities-in-the-ado-net-data-services-client-library.aspx
Alternatively, if you can get away with using "internal" rather than "public" on your property then it will not get persisted with the current SDK (but this might change in the future).
For version 2.0 of the Table Storage SDK there is a new way to achieve this.
You can now override the WriteEntity method on TableEntity and remove any entity properties that have an attribute on them. I derive from a class that does this for all my entities, like:
public class CustomSerializationTableEntity : TableEntity
{
public CustomSerializationTableEntity()
{
}
public CustomSerializationTableEntity(string partitionKey, string rowKey)
: base(partitionKey, rowKey)
{
}
public override IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
var entityProperties = base.WriteEntity(operationContext);
var objectProperties = this.GetType().GetProperties();
foreach (PropertyInfo property in objectProperties)
{
// see if the property has the attribute to not serialization, and if it does remove it from the entities to send to write
object[] notSerializedAttributes = property.GetCustomAttributes(typeof(NotSerializedAttribute), false);
if (notSerializedAttributes.Length > 0)
{
entityProperties.Remove(property.Name);
}
}
return entityProperties;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class NotSerializedAttribute : Attribute
{
}
Then you can make use of this class for your entities like
public class MyEntity : CustomSerializationTableEntity
{
public MyEntity()
{
}
public string MySerializedProperty { get; set; }
[NotSerialized]
public List<string> MyNotSerializedProperty { get; set; }
}

Resources