AsyncAPI enum with specific values - asyncapi

Is it possible to create an enum with specific values in AsyncAPI? In my legacy c# code theres an enum like this
public enum OrderStatus
{
Ordered = 30,
UnderDelivery = 40,
Deliveret = 50,
Cancelled = 99
}
I would like to create the same enum, with the same values in AsyncAPI. But it seems that you cannot specify the values in async API. Am I missing something? Is there an alternative solution?

It is not, or at least not in the general sense.
With AsyncAPI 2.4 you can define payloads with different schema formats (schemaFormat), by default this is an AsyncAPI Schema Object which is a superset of JSON Schema Draft 7. There might exist a schema format you can use that allows this, I just don't recall knowing one, for example not even JDT allows this.
Looking into JSON Schema Draft 7, you will not find it possible to define an enum value with an associated name such as Ordered and UnderDelivery. This means the only way to define it is something like this:
{
"title": "OrderStatus",
"type": "number",
"enum": [
30,
40,
50,
99
]
}
This is because JSON Schema focuses on validating JSON data, and in the JSON world, there is no such thing as an associated name to the enum value. That is entirely related to programming languages.
Solution
There are a couple of solutions and how you can proceed, let me highlight one way I see it could be achieved.
Specification Extensions
If you use the default AsyncAPI 2.4.0 Schema Object, AsyncAPI allows you to add your own extension such as:
{
"title": "OrderStatus",
"type": "number",
"enum": [
30,
40,
50,
99
],
"x-enumNames": {
30: "Ordered",
40: "UnderDelivery",
50: "Deliveret",
99: "Cancelled"
}
}
This will also work if you use pure JSON Schema draft 7 because any extra properties are allowed.
In newer versions of JSON Schema, they introduce something called vocabularies, which could standardize this feature. I started some work around a code generation vocabulary unfortunately, there are many other areas that need to be solved first, so I don't have the bandwidth to personally push it forward.
Generating the enum model
Regardless of how you actually define it with the specification, I expect you want tooling to generate the "accurate" enum model in code generation so here is one way to do it.
Modelina is an open-source tool that is being developed exactly for these cases. I have added an example test case to showcase how it could be done for Modelina v0.59.
Let me break the implementation down:
const generator = new CSharpGenerator({
presets: [
{
enum: {
item: ({model, item, content}) => {
// Lets see if an enum has any associated names
const hasCustomName = model.originalInput !== undefined && model.originalInput['x-enumNames'] !== undefined;
if (hasCustomName) {
// Lets see if the specific value has an associated name
const customName = model.originalInput['x-enumNames'][item];
if (customName !== undefined) {
return customName;
}
}
return content;
}
}
}
]
});
The Csharp generator is being instructed to use a custom preset (can be seen as a Node.js middleware) for the enum renderer. Here we add a middleware to overwrite the name of each enum "item"/value based on whether it has our extension or not.
This results in the following generated model:
public enum OrderStatus
{
Ordered,
UnderDelivery,
Deliveret,
Cancelled
}
public static class OrderStatusExtensions
{
public static dynamic GetValue(this OrderStatus enumValue)
{
switch (enumValue)
{
case OrderStatus.Ordered: return 30;
case OrderStatus.UnderDelivery: return 40;
case OrderStatus.Deliveret: return 50;
case OrderStatus.Cancelled: return 99;
}
return null;
}
public static OrderStatus? ToOrderStatus(dynamic value)
{
switch (value)
{
case 30: return OrderStatus.Ordered;
case 40: return OrderStatus.UnderDelivery;
case 50: return OrderStatus.Deliveret;
case 99: return OrderStatus.Cancelled;
}
return null;
}
}

Related

How to extend the jsonschema validator?

For my project I need a new property for json schemas.
I named it "isPropertyOf" and basically what I want is that if I have this:
fruits = {
"banana": "yellow fruit",
"apple": "round fruit"
}
schema = {
"type": "object",
"properties": {
"fav_fruit": {
"type": "string",
"isPropertyOf": fruits
}
}
}
Then schema would validate only objects like {"fav_fruit":"banana"} or {"fav_fruit":"apple"}, but not {"fav_fruit":"salami"}
(I know that for this very example using an enum would make more sense, but assume "fruits" is also used for other stuff and I would rather avoid redundancy)
I read docs about this and figured I need to use jsonschema.validators.extend. I tried something like that:
def is_property_of_callable(validator_instance, property_value, instance, schema):
keys = [k for k in property_value]
return instance in keys
mapping = {"isPropertyOf": is_property_of_callable}
my_validator = jsonschema.validators.extend(jsonschema.Draft7Validator, mapping)
instance = {"fav_fruit": "tobacco"}
my_validator(schema).is_valid(instance)
I was ready to see something go wrong, but apparently the validator wasn't seeing any issue. I tried with an obviously wrong instance that even the standard validator of jsonschema wouldn't accept
my_validator(schema).is_valid({"fav_fruit": 0})
But apparently it looked ok to it.
I thought maybe the way I added this property was so broken that it was making the validator accept anything, so I tried a minimal case of validator extension:
minimal_validator = jsonschema.validators.extend(jsonschema.Draft7Validator, {})
minimal_validator(schema).is_valid(instance)
And this one is also happy with 0 being my favourite fruit.
What am I doing wrong here? How can I make that work?

How to fetch GitHub branch names using GraphQL

Using GitHub GraphQL API (v.4) I would like to get all the branch names existing on a given repository.
My attempt
{
repository(name: "my-repository", owner: "my-account") {
... on Ref {
name
}
}
}
returns error:
{'data': None, 'errors': [{'message': "Fragment on Ref can't be spread inside Repository", 'locations': [{'line': 4, 'column': 13}]}]}
Here's how to retrieve 10 branches from a repo:
{
repository(name: "git-point", owner: "gitpoint") {
refs(first: 10, , refPrefix:"refs/heads/") {
nodes {
name
}
}
}
}
PS: You usually use spread when dealing with an Union type (like IssueTimeline for example, which is composed of different kind of objects, so you can spread on a particular object type to query specific fields.
You might need to use pagination to get all branches

PHPSpec: How to handle data heavy mocks in spec?

I have a series of specs that are doing what I would like them to but I'm wondering if I'm overcomplicating things as my let function for some of them is rather large and cumbersome.
I have built specs for a series of classes that process responses from SQL or JSON API depending on the response. The specs are just checking the resultant object of the processes of each class. I've mocked the connection to return valid mock data for each type of request that the specs would trigger. I'm trying to think of a better way to provide this mock data than having rather large arrays and JSON strings just sitting in the spec files.
For example (simplified):
class CharacterProcessorSpec extends ObjectBehavior
{
public function let(AdapterInterface $adapter)
{
$characters = [
[
'name' => 'Timmy',
'class' => 'Fighter',
'level' => 1,
'race' => 'Elf',
'str' => 16,
'dex' => 14,
'con' => 18,
'int' => 10,
'wis' => 12,
'cha' => 11,
... // Rest of the minimally required fields
], [
... // Second character for processing multiple at once
]
];
$adapter->fetch(new CharacterRequest('Timmy'))->willReturn([$characters[0]]);
$adapter->fetch(new CharacterRequest('*'))->willReturn($characters);
$this->beConstructedWith($adapter);
}
public function it_should_build_requested_character_details()
{
$this->build('Timmy')->shouldReturnArrayOfCharacters();
}
public function it_should_build_all_character_details()
{
$this->buildAll()->shouldReturnArrayOfCharacters();
}
public function getMatchers()
{
return [
'returnArrayOfCharacters' => function($characters) {
foreach ($characters as $c) {
if (!$c instanceof Character) {
return false;
}
}
return true;
}
];
}
}
Is it worth me moving the arrays to a separate file and loading them in or is that a no no?
Note: The build functions are designed to not care if the adapter is for SQL or the API, it just converts the data into a consistant object. Therefore the spec does not actually define what the data is (in the example I have provided it's the same as an SQL response but I usually have the second entry formatted how the JSON response would be as it processes on a per entry basis).
Is it worth me moving the arrays to a separate file and loading them in or is that a no no?
No, is not worth this effort. You provide only data to constructor and with that it should be OK in direct definitions.

Remove HATEOS from spring data rest? [duplicate]

Using Spring Data REST with JPA in version 2.0.2.RELEASE.
How can I disable Hypertext Application Language (HAL) in the JSON ? http://stateless.co/hal_specification.html
I have tried many things already, but to no avail. For example, I have set Accept and Content-type headers to "application/json" instead of "application/hal+json" but I still receive the JSON content with hyper links.
For example, I'd like to get something like:
{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"sector" : {
"description" : "Marketing",
"average profit": 545656665,
"average employees": 75,
"average profit per employee": 4556
}
}
Instead of:
{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"_links" : {
"self" : {
"href" : "http://localhost:8080/app/companies/1"
},
"sector" : {
"href" : "http://localhost:8080/app/companies/1/sector"
}
}
}
Thanks for your help.
(Hyper)media types
The default settings for Spring Data REST use HAL as the default hypermedia representation format, so the server will return the following for the given Accept headers:
No header -> application/hal+json -> HAL
application/hal+json -> application/hal+json -> HAL
application/json -> application/json -> HAL (this is what the default configures)
application/x-spring-data-verbose+json -> application/x-spring-data-verbose+json -> a Spring Data specific format (using links for the links container and content as wrapper for the collection items.
If you configure RepositoryRestConfiguration.setDefaultMediaType(…) to a non-HAL format, the server will return the Spring Data specific JSON format unless you explicitly ask for application/hal+json. Admittedly the configuration option is probably a bit misleading, so I filed DATAREST-294 to improve this. The issue was resolved in 2.1 RC1 (Dijkstra) 2014.
Note that we effectively need a hypermedia format in place to be able to express relations between managed resources and enable discoverability of the server. So there's no way you'll be able to get rid of it completely. This is mostly due to the fact that you could easily crash the server if you expose entities that have bidirectional relationships or make up an enormous object graph.
Inlining related entities
If you never want to have sectors linked to and always inline them, one option is to simply exclude the SectorRepository from being exported as a REST resource in the first place. You can achieve this by annotating the repository interface with #RepositoryRestResource(exported = false).
To get a representation returned as you posted in your lower example have a look at the projections feature introduced in Spring Data REST 2.1 M1. It basically allow you to craft optional views on a resource that can differ from the default one via a simple interface.
You'd basically define an interface:
#Projection(name = "foo", types = YourDomainClass.class)
interface Inlined {
// list all other properties
Sector getSector();
}
If you either put this interface into a (sub)package of your domain class or manually register it via RepositoryRestConfiguration.projectionConfiguration() the resources exposing YourDomainClass will accept a request parameter projection so that passing in foo in this example would render the inlined representation as you want it.
This commit has more info on the feature in general, this commit has an example projection defined.
So you want 2 things:
1) get rid of _links field
2) include the related sector field
Possible solution (works for me :D)
1) get rid of _links
For this create the class below:
[... package declaration, imports ...]
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
public MyRepositoryRestMvcConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService) {
super(context, conversionService);
}
#Bean
protected LinkCollector linkCollector() {
return new LinkCollector(persistentEntities(), selfLinkProvider(), associationLinks()) {
public Links getLinksFor(Object object, List<Link> existingLinks) {
return new Links();
}
};
}
}
and use it e.g.:
[... package declaration, imports ...]
#SpringBootApplication
#Import({MyRepositoryRestMvcConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I'm pretty sure (99%, but not tested) that you won't need this class for removing the _links for the related entity/entities included the way next point (2) is showing.
2) include the related sector field
For this you could use Excerpts (especially made for this scenario). Because the Spring example is so eloquent and it's silly to just copy it here I'll just point it: https://docs.spring.io/spring-data/rest/docs/3.1.x/reference/html/#projections-excerpts.excerpting-commonly-accessed-data.
But just for the record and your convenience I'll paste the main parts of the spring example:
#Projection(name = "inlineAddress", types = { Person.class })
interface InlineAddress {
String getFirstName();
String getLastName();
Address getAddress();
}
see at Projection javadoc that types means The type the projection type is bound to.
The excerpt could be used this way:
#RepositoryRestResource(excerptProjection = InlineAddress.class)
interface PersonRepository extends CrudRepository<Person, Long> {}
in order to get this (when also using MyRepositoryRestMvcConfiguration):
{
"firstName" : "Frodo",
"lastName" : "Baggins",
"address" : {
"street": "Bag End",
"state": "The Shire",
"country": "Middle Earth"
}
}
For you the sector is the equivalent of address.
Final notes
When returning arrays the _links field won't be removed (it's too intrusive to do it); in the end you'll have something like this:
{
"_embedded" : {
"persons" : [ {person1}, {person2}, ..., {personN} ]
},
"_links" : {
e.g. first, next, last, self, profile
},
"page" : {
"size" : 1,
"totalElements" : 10,
"totalPages" : 10,
"number" : 0
}
}
As you can see even if we'd have _links removed that still won't be enough; one would probably also want _embedded replaced by persons which would lead to less maintainable code (too much spring intrusive overrides). But if one really wants these too he should start checking RepositoryRestMvcConfiguration and RepositoryEntityController.getCollectionResource.
Spring is evolving so I feel the need to point that this works with at least:
spring-data-rest-webmvc 3.1.3.RELEASE
or, if you prefeer spring boot version:
spring-boot-starter-parent 2.1.1.RELEASE
If you want to delete _links do the following (worked for me):
Go to your pom.xml and delete the following dependency:
spring-boot-starter-data-rest
Make an "Update project" to update the pom.xml changes.
Now it will be use your own controller for the api rest, deleting _self, _links..., that alike this:
[... package declaration, imports ...]
#RestController
#RequestMapping("/series")
public class SerieController {
#Autowired
private SerieRepositorio serieRepositorio;
public SerieController(SerieRepositorio serieRepositorio) {
this.serieRepositorio = serieRepositorio;
}
#GetMapping
public Iterable<Serie> getAllSeries() {
return serieRepositorio.findAll();
}
}

NUnit - Multiple properties of the same name? Linking to requirements

I'm linking all our our System Tests to test cases and to our Requirements. Every requirement has an ID. Every Test Case / System Tests tests a variety of requirements. Every module of code links to multiple requirements.
I'm trying to find the best way to link every system test to its driving requirements.
I was hoping to do something like:
[NUnit.Framework.Property("Release", "6.0.0")]
[NUnit.Framework.Property("Requirement", "FR50082")]
[NUnit.Framework.Property("Requirement", "FR50084")]
[NUnit.Framework.Property("Requirement", "FR50085")]
[TestCase(....)]
public void TestSomething(string a, string b...)
However, that will break because Property is a Key-Value pair. The system will not allow me to have multiple Properties with the same key.
The reason I'm wanting this is to be able to test specific requirements in our system if a module changes that touches these requirements.
Rather than run over 1,000 system tests on every build, this would allow us to target what to test based on changes done to our code.
Some system tests run upwards of 5 minutes (Enterprise healthcare system), so "Just run all of them" isn't a viable solution. We do that, but only before promoting through our environments.
Thoughts?
Have you considered a custom property attribute derived from NUnit.Framework.Property?
Something like the following seems like it might work for you judging by a LINQPad 4 "query" with Language set to C# Program and a reference to nunit.framework.dll (version 2.4.8) added:
// main method to exercise a our PoC test case
void Main()
{
TestSomething("a", "b");
}
// our PoC custom property attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class RequirementsAttribute : NUnit.Framework.PropertyAttribute
{
public RequirementsAttribute(string[] requirements)
: base(requirements)
{
}
}
// a test case using our custom property attribute to relate it to multiple requirements
[Requirements(new string[] { "FR50082", "FR50084" })]
[TestCase("PoCTest")]
public void TestSomething(string a, string b)
{
// blah, blah, blah
Assert.AreNotEqual(a, b);
}
For some reason I could not add the link to the google discussion post to the comment above, so I have added the post here too. (The link is https://groups.google.com/forum/#!topic/nunit-discuss/ndV3VTPndck)
A Category is always displayed in TE as "Category [xxxxxxx]", where xxxxx is whatever string you send in, if you don't specify any, it will be the name of the class derived from CategoryAttribute.
If you want to use Category, you should, as Charlie said on the google post, use one entry per requirement. If you add the string Requirement to the value, it can look pretty good, but most follow the rules in (1) above, it could be like:
Category[Requirement:FR12345]
Code:
public class RequirementAttribute : CategoryAttribute
{
public RequirementAttribute(string s)
: base("Requirement:" + s)
{ }
}
If you want it to display like : Requirement[FR12345], then you MUST use a Property, but you can't have multiple Keys, so only one such per test.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string s)
: base(s)
{}
}
4: If you want to have multiple requirements per test and still have something like the display in (3), you must make the keys unique. It doesn't need to look too bad. In the code below I have just added a counter to it.
It will display as :
Requirement-1[FR12345]
Requirement-2[FR23456]
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
int i = 0;
foreach (var s in array)
{
Properties.Add("Requirement-" + i, s);
i++;
}
}
}
and you use it like:
[Requirement(new[] { "1234", "2345" })]
[Test]
public void Test()
{ }
(And if you want a syntax without the "new", the previous answer show that syntax with the param instead.)
Option 4 will not group by requirement number, but by the counter. If you want to group by requirement number you can use option 5:
5.
Add the requirement number to the key, but leave the value blank.
It will look like:
Requirement-FR12345
In this way, you also skip the prefix and have each requirement as its own kind of category in the TE.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
foreach (var s in array)
{
Properties.Add("Requirement-" + s,"");
}
}
}
And, you could of course also skip the prefix altogether.