Customise WebAPI response like Status, Data, message formate - asp.net-web-api

How can i customise WebAPI 2 response like status, data, message in JSON format
Successful request:
{
"status": "success",
"data": {
/* Application-specific data would go here. */
},
"message": null /* Or optional success message */
}
Failed request:
{
"status": "error",
"data": null, /* or optional error payload */
"message": "Error xyz has occurred"
}

Define a new class like :
public class ResponseDto
{
public string status { get; set; }
public dynamic data { get; set; }
public string message { get; set; }
}
and then populate the properties with respective values and do :
var response = new ResponseDto()
{
response.status = " ",
response.data = obj,
response.message = " "
}
and then from the controller method(API),
return response;
Your JSON formatter will then convert the response object into JSON string.

Related

{"$":["'i' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."],"request":["The request field is required."]}}

I'm simply trying to send this AJAX request to my controller but keep ending up with the error in the title, Everything works fine on swagger API so I'm assuming somehow I'm passing the data wrong on the ajax request? here is the request:
function submitForm(){
var fullName = $("#name").find(":selected").val();
console.log(fullName);
var firstName = fullName.split(' ').slice(0, -1).join(' ');
console.log(firstName);
var lastName = fullName.split(' ').slice(-1).join(' ');
console.log(lastName);
console.log($("#name").find(":selected").attr("name"));
var formData = {
id: null,
type: 2,
person: $("#name").find(":selected").attr("name"),
firstName: firstName,
lastName: lastName,
dateCreated: new Date().toISOString(),
dateModified: new Date().toISOString(),
modifiedBy: "Web Application"
};
console.log(formData);
$.ajax({
type: "POST",
url: 'https://localhost:44398/api/Attendee1/InsertAttendee',
data: formData,
contentType: 'application/json',
success: function(res){
console.log(res)
}
});
}
Here is my Controller
[HttpPost("InsertAttendee")]
public async Task<ActionResult<Attendee2>> InsertAttendee(Attendee2 request, CancellationToken cancellationToken)
{
Attendee2 Attendee2 = new Attendee2();
Attendee2.Type = request.Type;
Attendee2.Person = request.Person;
Attendee2.FirstName = request.FirstName;
Attendee2.LastName = request.LastName;
Attendee2.DateCreated = request.DateCreated;
Attendee2.DateModified = request.DateModified;
Attendee2.ModifiedBy = request.ModifiedBy;
var returnedId = new OutputParameter<int?>();
try
{
await _context.GetProcedures().InsertAttendeeAsync(Attendee2.DateCreated, Attendee2.DateModified, Attendee2.FirstName, Attendee2.LastName, Attendee2.ModifiedBy, Attendee2.Person, Attendee2.Type, returnedId, null, cancellationToken);
}
catch(Exception ex)
{
return StatusCode(500, ex);
}
return CreatedAtAction("GetAttendee1", new { id = Attendee2.Id }, Attendee2);
}
Attendee 2 Model
public class Attendee2
{
[Key]
public int Id { get; set; }
public int Type { get; set; }
public int? Person { get; set; }
[StringLength(100)]
[Unicode(false)]
public string FirstName { get; set; }
[StringLength(100)]
[Unicode(false)]
public string LastName { get; set; }
[Column(TypeName = "datetime")]
public DateTime DateCreated { get; set; }
[Column(TypeName = "datetime")]
public DateTime DateModified { get; set; }
[Required]
[StringLength(50)]
[Unicode(false)]
public string ModifiedBy { get; set; }
}
Full Error: {"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-f5e0489cf9bb95269b878874ccb4e152-3003e7f9f1a70d1d-00","errors":{"$":["'i' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."],"request":["The request field is required."]}}
The Solution was to JSON.Stringify(formData).

Swagger Bearer Authentication isn't showing Authorization JWT token field for [GET] request

Authorization field is showing for HTTP POST request but it's not showing for GET request to add a token for authentication of Web API.
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Mach.CharterPad.API");
c.OperationFilter<SwaggerAuthorizationFilter>();
c.RootUrl(req => $"{req.RequestUri.GetLeftPart(UriPartial.Authority)}{req.GetConfiguration().VirtualPathRoot.TrimEnd('/')}{appvirtualpath}/api");
}).EnableSwaggerUi();
public class SwaggerAuthorizationFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
if (operation.parameters != null)
{
operation.parameters.Add(new Parameter
{
name = "Authorization",
#in = "header",
description = "access token",
required = false,
type = "string"
});
}
}
}
I have updated API parameters and it's working fine.
[Route("")]
public IHttpActionResult Get([FromUri] Paging paging)
{
var result = TripManager.Get(paging.Index, paging.Size);
return Ok(result != null ? new ApiResponse(true, "Results found", result) : new ApiResponse(false, "No record found", result));
}

MongoDB search nested objects in an array

I am using MongoDB to store all the events in my Eventbrite clone. So I have a collection called events then the objects in this collection consists of their name and and array of users that have rsvp to the event. I can query for any events that the current user has created but unable to figure out how to query both events the user has created and rsvp to.
Here is the compiled query that I am using to try to get all the users events.
events.find({"$and":[{"user_id":"5d335704802df000076bad97"},{"user_id":{"$ne":null}}],"$or":[{"checkins.user_id":"5d335704802df000076bad97"}]},{"typeMap":{"root":"array","document":"array"}})
I am using the Laravel MongoDB plugin to query my data in php it looks like this
$user->events()->orWhere(function ($query) use ($user){
return $query->where('checkins.user_id',new ObjectID($user->id));
})->get()
The event object looks something like this:
{
"name": "test",
"user_id": "1"
"rsvp": [
{"user_id": "12"}
]
}
An user can rsvp to other event that are not their own.
you need an $or filter and $elemMatch to get events that belong to a given user or events they've rsvp'd to.
db.events.find({
"$or": [
{
"user_id": "5d33e732e1ea9d0d6834ef3d"
},
{
"rsvp": {
"$elemMatch": {
"user_id": "5d33e732e1ea9d0d6834ef3d"
}
}
}
]
})
unfortunately i can't help you with laravel version of the query. in case it helps, below is the c# code that generated the above mongo query.
using MongoDB.Entities;
using System.Linq;
namespace StackOverflow
{
public class Program
{
public class user : Entity
{
public string name { get; set; }
}
public class Event : Entity
{
public string name { get; set; }
public string user_id { get; set; }
public rsvp[] rsvp { get; set; }
}
public class rsvp
{
public string user_id { get; set; }
}
private static void Main(string[] args)
{
new DB("test");
var mike = new user { name = "mike" };
var dave = new user { name = "dave" };
mike.Save();
dave.Save();
(new[] {
new Event
{
name = "mike's event",
user_id = mike.ID,
rsvp = new[]
{
new rsvp { user_id = dave.ID }
}
},
new Event
{
name = "dave's event",
user_id = dave.ID,
rsvp = new[]
{
new rsvp { user_id = mike.ID }
}
}
}).Save();
var result = DB.Find<Event>()
.Many(e =>
e.user_id == mike.ID ||
e.rsvp.Any(r => r.user_id == mike.ID));
}
}
}

OData 4 web api 2 "No routing convention was found"

I'm trying to post object to odata action, here my code
public class DraftController : ODataController
{
public HttpResponseMessage Attachment([FromODataUri] string key, [FromBody] DraftApi d)
{
try
{
return Request.CreateResponse(HttpStatusCode.Created, "(POST ATTACHMENT) key: " + key + " - id: " + d.id + ", desc: " + d.description);
}
catch (Exception e)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
}
}
}
this is my model
public class DraftApi
{
[Key]
public string id { get; set; }
public string description { get; set; }
}
this is my OData route
config.MapODataServiceRoute(
routeName: "ODataDraft",
routePrefix: "odata/{namespace}",
model: BuildModel<DraftApi>("draft")
);
private static IEdmModel BuildModel<T>(string EntityName) where T : class
{
ODataConventionModelBuilder ODataBuilder = new ODataConventionModelBuilder();
ODataBuilder.EntitySet<T>(EntityName).EntityType.Name = EntityName;
ActionConfiguration attachment = ODataBuilder.EntityType<T>().Action("Attachment");
ODataBuilder.EnableLowerCamelCase();
return ODataBuilder.GetEdmModel();
}
my call is this
Url
http://127.0.0.1/mpssapi/odata/v1/draft('hhh')/Attachment
Headers
Content-Type: application/json
Payload
{id:"a", description: "abc"}
This is my response
{
"error": {
"code": ""
"message": "No HTTP resource was found that matches the request URI 'http://127.0.0.1/mpssapi/odata/v1/draft('hhh')/Attachment'."
"innererror": {
"message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'."
"type": ""
"stacktrace": ""
}-
}-
}
I have tried to add namespace to odata route but it doesn't work
any ideas?
thanks
The doc may help: http://odata.github.io/WebApi/#04-07-action-parameter-support
and call without namespace, you need to turn on UnqualifiedNameCall option like:
config.EnableUnqualifiedNameCall(true);

Asp.Net MVC 3 ModelBinding Arrays

I am posting something that looks like this:
FavoritePerson: "Dennis"
FavoriteAnimals: [{Type="Bear", Name="Bruno"}, {Type="Shark", Name="Sammy"}, ...]
Is there some shape for the Model to be that the DefaultModelBinder would be able to handle this? Something like
class FavoriteAnimalSubmission {
string Type {get; set;}
string Name {get; set;}
}
[HttpPost]
public MarkFavorites(string favoritePerson, FavoriteAnimalSubmission[] favoriteAnimals[]) {
...
}
Will fill favoritePerson and favoriteAnimals.Count but not the properties on each animal.
There is nothing out of the box that will handle a mixture of JSON (which in your case is invalid) and standard url encoded parameters. You will have to write a custom model binder if you ever needed to handle this request. Or simply modify your request to:
{
"FavoriteAnimals": [
{
"Type": "Bear",
"Name": "Bruno"
},
{
"Type": "Shark",
"Name": "Sammy"
}
],
"FavoritePerson": "Dennis"
}
and then on the server:
public class MyViewModel
{
public string FavoritePerson { get; set; }
public FavoriteAnimalSubmission[] FavoriteAnimals { get; set; }
}
public class FavoriteAnimalSubmission
{
public string Type { get; set; }
public string Name { get; set; }
}
and your controller action:
[HttpPost]
public MarkFavorites(MyViewModel model)
{
...
}
and the AJAX request to invoke it:
var model =
{
"FavoriteAnimals": [
{
"Type": "Bear",
"Name": "Bruno"
},
{
"Type": "Shark",
"Name": "Sammy"
}
],
"FavoritePerson": "Dennis"
};
$.ajax({
url: '#Url.Action("MarkFavorites", "SomeController")',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(model),
success: function(result) {
// do something with the result
}
});

Resources