Skip to content

Commit ebd5cc3

Browse files
Add more demo API endpoints and integration tests
1 parent 2e90e10 commit ebd5cc3

File tree

111 files changed

+8078
-347
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+8078
-347
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using ReQuesty.Demo.Api.Controllers.Base;
3+
using ReQuesty.Demo.Api.Models;
4+
5+
namespace ReQuesty.Demo.Api.Controllers;
6+
7+
/// <summary>
8+
/// A controller to test the behavior of request body parameters (POST, PUT, PATCH, DELETE)
9+
/// </summary>
10+
public class BodyParameterController : DemoControllerBase
11+
{
12+
/// <summary>
13+
/// Accepts a SomeObject body and returns it with 201 Created.
14+
/// </summary>
15+
/// <param name="body">The object to create.</param>
16+
/// <returns></returns>
17+
[HttpPost("object", Name = "PostObject")]
18+
[ProducesResponseType<SomeObject>(StatusCodes.Status201Created)]
19+
public async ValueTask<ActionResult<SomeObject>> PostObjectAsync([FromBody] SomeObject body)
20+
{
21+
return StatusCode(StatusCodes.Status201Created, body);
22+
}
23+
24+
/// <summary>
25+
/// Accepts a SomeObject body and returns it with 200 OK.
26+
/// </summary>
27+
/// <param name="id">The ID of the object to replace.</param>
28+
/// <param name="body">The replacement object.</param>
29+
/// <returns></returns>
30+
[HttpPut("object/{id:guid}", Name = "PutObject")]
31+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
32+
public async ValueTask<ActionResult<SomeObject>> PutObjectAsync([FromRoute] Guid id, [FromBody] SomeObject body)
33+
{
34+
return body with { Id = id };
35+
}
36+
37+
/// <summary>
38+
/// Accepts a SomeObject body and returns the merged result with 200 OK.
39+
/// </summary>
40+
/// <param name="id">The ID of the object to patch.</param>
41+
/// <param name="body">The partial object to merge.</param>
42+
/// <returns></returns>
43+
[HttpPatch("object/{id:guid}", Name = "PatchObject")]
44+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
45+
public async ValueTask<ActionResult<SomeObject>> PatchObjectAsync([FromRoute] Guid id, [FromBody] SomeObject body)
46+
{
47+
return body with { Id = id };
48+
}
49+
50+
/// <summary>
51+
/// Deletes an object by ID and returns 204 No Content.
52+
/// </summary>
53+
/// <param name="id">The ID of the object to delete.</param>
54+
/// <returns></returns>
55+
[HttpDelete("object/{id:guid}", Name = "DeleteObject")]
56+
[ProducesResponseType(StatusCodes.Status204NoContent)]
57+
public async ValueTask<ActionResult> DeleteObjectAsync([FromRoute] Guid id)
58+
{
59+
return NoContent();
60+
}
61+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using ReQuesty.Demo.Api.Controllers.Base;
3+
using ReQuesty.Demo.Api.Models;
4+
5+
namespace ReQuesty.Demo.Api.Controllers;
6+
7+
/// <summary>
8+
/// A controller to test the behavior of collection return types
9+
/// </summary>
10+
public class CollectionReturnController : DemoControllerBase
11+
{
12+
#region Integer Arrays
13+
/// <summary>
14+
/// Gets an int array based on the specified return type.
15+
/// </summary>
16+
/// <returns></returns>
17+
[HttpGet("integers", Name = "GetIntArray")]
18+
[ProducesResponseType<int[]>(StatusCodes.Status200OK)]
19+
public async ValueTask<ActionResult<int[]>> GetIntArrayAsync([FromQuery] ReturnType returnType)
20+
{
21+
return Ok(returnType switch
22+
{
23+
ReturnType.Null => null,
24+
ReturnType.Random => new[] { Random.Shared.Next(), Random.Shared.Next(), Random.Shared.Next() },
25+
ReturnType.Invalid => "not an array",
26+
_ => throw new()
27+
});
28+
}
29+
30+
/// <summary>
31+
/// Gets a nullable int array based on the specified return type.
32+
/// </summary>
33+
/// <returns></returns>
34+
[HttpGet("integers/nullable", Name = "GetNullableIntArray")]
35+
[ProducesResponseType<int[]>(StatusCodes.Status200OK)]
36+
public async ValueTask<ActionResult<int[]?>> GetNullableIntArrayAsync([FromQuery] ReturnType returnType)
37+
{
38+
return Ok(returnType switch
39+
{
40+
ReturnType.Null => null,
41+
ReturnType.Random => new[] { Random.Shared.Next(), Random.Shared.Next(), Random.Shared.Next() },
42+
ReturnType.Invalid => "not an array",
43+
_ => throw new()
44+
});
45+
}
46+
#endregion
47+
48+
#region String Lists
49+
/// <summary>
50+
/// Gets a list of strings based on the specified return type.
51+
/// </summary>
52+
/// <returns></returns>
53+
[HttpGet("strings", Name = "GetStringList")]
54+
[ProducesResponseType<List<string>>(StatusCodes.Status200OK)]
55+
public async ValueTask<ActionResult<List<string>>> GetStringListAsync([FromQuery] ReturnType returnType)
56+
{
57+
return Ok(returnType switch
58+
{
59+
ReturnType.Null => null,
60+
ReturnType.Random => new List<string> { Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Guid.NewGuid().ToString() },
61+
ReturnType.Invalid => "not a list",
62+
_ => throw new()
63+
});
64+
}
65+
66+
/// <summary>
67+
/// Gets a nullable list of strings based on the specified return type.
68+
/// </summary>
69+
/// <returns></returns>
70+
[HttpGet("strings/nullable", Name = "GetNullableStringList")]
71+
[ProducesResponseType<List<string>>(StatusCodes.Status200OK)]
72+
public async ValueTask<ActionResult<List<string>?>> GetNullableStringListAsync([FromQuery] ReturnType returnType)
73+
{
74+
return Ok(returnType switch
75+
{
76+
ReturnType.Null => null,
77+
ReturnType.Random => new List<string> { Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Guid.NewGuid().ToString() },
78+
ReturnType.Invalid => "not a list",
79+
_ => throw new()
80+
});
81+
}
82+
#endregion
83+
84+
#region Object Lists
85+
/// <summary>
86+
/// Gets a list of SomeObject based on the specified return type.
87+
/// </summary>
88+
/// <returns></returns>
89+
[HttpGet("objects", Name = "GetObjectList")]
90+
[ProducesResponseType<List<SomeObject>>(StatusCodes.Status200OK)]
91+
public async ValueTask<ActionResult<List<SomeObject>>> GetObjectListAsync([FromQuery] ReturnType returnType)
92+
{
93+
return Ok(returnType switch
94+
{
95+
ReturnType.Null => null,
96+
ReturnType.Random => new List<SomeObject>
97+
{
98+
new()
99+
{
100+
Id = Guid.NewGuid(),
101+
Name = "Object One",
102+
Age = 10,
103+
RequestedAt = DateTimeOffset.UtcNow,
104+
Cost = 1.0
105+
},
106+
new()
107+
{
108+
Id = Guid.NewGuid(),
109+
Name = "Object Two",
110+
Age = 20,
111+
RequestedAt = DateTimeOffset.UtcNow,
112+
Cost = 2.0
113+
},
114+
},
115+
ReturnType.Invalid => "not a list",
116+
_ => throw new()
117+
});
118+
}
119+
120+
/// <summary>
121+
/// Gets a nullable list of SomeObject based on the specified return type.
122+
/// </summary>
123+
/// <returns></returns>
124+
[HttpGet("objects/nullable", Name = "GetNullableObjectList")]
125+
[ProducesResponseType<List<SomeObject>>(StatusCodes.Status200OK)]
126+
public async ValueTask<ActionResult<List<SomeObject>?>> GetNullableObjectListAsync([FromQuery] ReturnType returnType)
127+
{
128+
return Ok(returnType switch
129+
{
130+
ReturnType.Null => null,
131+
ReturnType.Random => new List<SomeObject>
132+
{
133+
new()
134+
{
135+
Id = Guid.NewGuid(),
136+
Name = "Object One",
137+
Age = 10,
138+
RequestedAt = DateTimeOffset.UtcNow,
139+
Cost = 1.0
140+
},
141+
new()
142+
{
143+
Id = Guid.NewGuid(),
144+
Name = "Object Two",
145+
Age = 20,
146+
RequestedAt = DateTimeOffset.UtcNow,
147+
Cost = 2.0
148+
},
149+
},
150+
ReturnType.Invalid => "not a list",
151+
_ => throw new()
152+
});
153+
}
154+
#endregion
155+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using ReQuesty.Demo.Api.Controllers.Base;
3+
using ReQuesty.Demo.Api.Models;
4+
5+
namespace ReQuesty.Demo.Api.Controllers;
6+
7+
/// <summary>
8+
/// A controller to demonstrate handling of path parameters in ReQuesty.
9+
/// </summary>
10+
public class PathParameterController : DemoControllerBase
11+
{
12+
/// <summary>
13+
/// Gets a SomeObject based on the specified return type.
14+
/// </summary>
15+
/// <param name="integerId">The integer ID to determine the return type.</param>
16+
/// <returns></returns>
17+
[HttpGet("integerId/{integerId:int}", Name = "GetSomeObjectByIntegerId")]
18+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
19+
public async ValueTask<ActionResult<SomeObject>> GetSomeObjectByIntegerIdAsync([FromRoute] int integerId)
20+
{
21+
return new SomeObject
22+
{
23+
Id = Guid.NewGuid(),
24+
Name = "Sample Object",
25+
Age = 25,
26+
RequestedAt = DateTimeOffset.UtcNow,
27+
Cost = 100.0
28+
};
29+
}
30+
31+
/// <summary>
32+
/// Gets a SomeObject based on the specified return type.
33+
/// </summary>
34+
/// <param name="guidId">The GUID ID to determine the return type.</param>
35+
/// <returns></returns>
36+
[HttpGet("guidId/{guidId:guid}", Name = "GetSomeObjectByGuidId")]
37+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
38+
public async ValueTask<ActionResult<SomeObject>> GetSomeObjectByGuidIdAsync([FromRoute] Guid guidId)
39+
{
40+
return new SomeObject
41+
{
42+
Id = guidId,
43+
Name = "Sample Object",
44+
Age = 25,
45+
RequestedAt = DateTimeOffset.UtcNow,
46+
Cost = 100.0
47+
};
48+
}
49+
50+
/// <summary>
51+
/// Gets a SomeObject based on a string ID path parameter.
52+
/// </summary>
53+
/// <param name="stringId">The string ID.</param>
54+
/// <returns></returns>
55+
[HttpGet("stringId/{stringId}", Name = "GetSomeObjectByStringId")]
56+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
57+
public async ValueTask<ActionResult<SomeObject>> GetSomeObjectByStringIdAsync([FromRoute] string stringId)
58+
{
59+
return new SomeObject
60+
{
61+
Id = Guid.NewGuid(),
62+
Name = stringId,
63+
Age = 25,
64+
RequestedAt = DateTimeOffset.UtcNow,
65+
Cost = 100.0
66+
};
67+
}
68+
69+
/// <summary>
70+
/// Gets a SomeObject based on a long ID path parameter.
71+
/// </summary>
72+
/// <param name="longId">The long ID.</param>
73+
/// <returns></returns>
74+
[HttpGet("longId/{longId:long}", Name = "GetSomeObjectByLongId")]
75+
[ProducesResponseType<SomeObject>(StatusCodes.Status200OK)]
76+
public async ValueTask<ActionResult<SomeObject>> GetSomeObjectByLongIdAsync([FromRoute] long longId)
77+
{
78+
return new SomeObject
79+
{
80+
Id = Guid.NewGuid(),
81+
Name = $"Object {longId}",
82+
Age = 25,
83+
RequestedAt = DateTimeOffset.UtcNow,
84+
Cost = longId
85+
};
86+
}
87+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using ReQuesty.Demo.Api.Controllers.Base;
3+
using ReQuesty.Demo.Api.Models.Animals;
4+
5+
namespace ReQuesty.Demo.Api.Controllers;
6+
7+
/// <summary>
8+
/// A controller to test the behavior of polymorphic request and response body types
9+
/// </summary>
10+
public class PolymorphicController : DemoControllerBase
11+
{
12+
/// <summary>
13+
/// Accepts an AnimalBase body and echoes it back, verifying polymorphic round-trip.
14+
/// </summary>
15+
/// <param name="body">The animal to echo.</param>
16+
/// <returns></returns>
17+
[HttpPost("animal", Name = "PostAnimal")]
18+
[ProducesResponseType<AnimalBase>(StatusCodes.Status200OK)]
19+
public async ValueTask<ActionResult<AnimalBase>> PostAnimalAsync([FromBody] AnimalBase body)
20+
{
21+
return body;
22+
}
23+
24+
/// <summary>
25+
/// Accepts a List&lt;AnimalBase&gt; and echoes it back, verifying polymorphic round-trip.
26+
/// </summary>
27+
/// <param name="body">The animal to echo.</param>
28+
/// <returns></returns>
29+
[HttpPost("animal/bulk", Name = "PostAnimalList")]
30+
[ProducesResponseType<List<AnimalBase>>(StatusCodes.Status200OK)]
31+
public async ValueTask<ActionResult<List<AnimalBase>>> PostAnimalListAsync([FromBody] List<AnimalBase> body)
32+
{
33+
return body;
34+
}
35+
36+
/// <summary>
37+
/// Accepts a Dog body and echoes it back.
38+
/// </summary>
39+
/// <param name="body">The dog to echo.</param>
40+
/// <returns></returns>
41+
[HttpPost("dog", Name = "PostDog")]
42+
[ProducesResponseType<Dog>(StatusCodes.Status200OK)]
43+
public async ValueTask<ActionResult<Dog>> PostDogAsync([FromBody] Dog body)
44+
{
45+
return body;
46+
}
47+
48+
/// <summary>
49+
/// Accepts a Dog body and echoes it back.
50+
/// </summary>
51+
/// <param name="body">The dog to echo.</param>
52+
/// <returns></returns>
53+
[HttpPost("dog/bulk", Name = "PostDogList")]
54+
[ProducesResponseType<List<Dog>>(StatusCodes.Status200OK)]
55+
public async ValueTask<ActionResult<List<Dog>>> PostDogListAsync([FromBody] List<Dog> body)
56+
{
57+
return Ok(body);
58+
}
59+
60+
/// <summary>
61+
/// Accepts a Dog body and echoes it back, as an AnimalBase.
62+
/// </summary>
63+
/// <param name="body">The dog to echo.</param>
64+
/// <returns></returns>
65+
[HttpPost("dog-animal", Name = "PostDogGetAnimal")]
66+
[ProducesResponseType<AnimalBase>(StatusCodes.Status200OK)]
67+
public async ValueTask<ActionResult<AnimalBase>> PostDogGetAnimalAsync([FromBody] Dog body)
68+
{
69+
return body;
70+
}
71+
72+
/// <summary>
73+
/// Accepts a Dog body and echoes it back, as an AnimalBase.
74+
/// </summary>
75+
/// <param name="body">The dog to echo.</param>
76+
/// <returns></returns>
77+
[HttpPost("dog-animal/bulk", Name = "PostDogListGetAnimalList")]
78+
[ProducesResponseType<List<AnimalBase>>(StatusCodes.Status200OK)]
79+
public async ValueTask<ActionResult<List<AnimalBase>>> PostDogListGetAnimalListAsync([FromBody] List<Dog> body)
80+
{
81+
return Ok(body);
82+
}
83+
}

0 commit comments

Comments
 (0)