How to hit Firebase HTTP protocol with Retrofit? - firebase-cloud-messaging

I want o post data on https://fcm.googleapis.com/fcm/send
along with two headers in Retrofit
Data to be sent
{
"data" : {
"title": "My Title",
"content": "My message"
},
"to": "cKA7LrjBQ6s:APA91bHtY6RBwZ4KZvxbl9VNZMVKz5_NDbE2dP3zgrhJNBSAKDyfOAbfxEi8pnAwc82pzLoGEZImZBv9MXvoBSJy6c0790oqUIYLECCU5WZVcGeSJJNECX5bsLMutYrSPjLSDffP5N3u"
}

It's very simple. Create the following classes.
public interface RestInterface {
#Headers({
"Content-Type: application/json",
"Authorization: key=<YOUR_FCM_SERVER_KEY_HERE>"
})
#POST("fcm/send")
Call<ResponseBody> sendNotification(#Body NotificationBody body);
}
Replace <YOUR_FCM_SERVER_KEY_HERE> with your actual FCM server key.
public class NotificationBody {
#SerializedName("data")
private Data data;
#SerializedName("to")
private String to;
public NotificationBody(Data data, String to) {
this.data = data;
this.to = to;
}
}
Above POJO class will generate outer JSONObject in run-time. And the following POJO class will generate data JSONObject.
public class Data {
#SerializedName("title")
private String title;
#SerializedName("content")
private String content;
public Data(String title, String content) {
this.title = title;
this.content = content;
}
}
And finally use above code in your Activity/Fragment classes like below,
String title = "My Title";
String content = "My message";
String to = "cKA7LrjBQ6s:APA91bHtY6RBwZ4KZvxbl9VNZMVKz5_NDbE2dP3zgrhJNBSAKDyfOAbfxEi8pnAwc82pzLoGEZImZBv9MXvoBSJy6c0790oqUIYLECCU5WZVcGeSJJNECX5bsLMutYrSPjLSDffP5N3u";
Data data = new Data(title, content);
NotificationBody body = new NotificationBody(data, to);
RestInterface api = ....;
Call<ResponseBody> call = api.sendNotification(body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, final Response<ResponseBody> response) {
// do whatever you want to do
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("TAG", "Error: ", t);
}
});
And don't forget to set Retrofit BASE_URL to https://fcm.googleapis.com/

Related

How do you manage the visible input fields accepted in an API HttpPost request?

In my API I have a Create method in my controller that accepts all of the models fields, but in the method I'm excluding the ID field since on a create it's generated. But in Swagger it's showing the following.
Is there a way for it not to show the following part?
"id": 0
Is a viewmodel how I should go about this?
I tried the following, but can't get it to work.
public class PartVM
{
public string Name { get; set; }
}
public interface IPartService
{
Task<Part> CreatePart(PartVM part);
Task<IEnumerable<Part>> GetParts();
Task<Part> GetPart(int partId);
}
public class PartService : IPartService
{
private readonly AppDbContext _appDbContext;
public PartService(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}
public async Task<Part> CreatePart(PartVM part)
{
var _part = new Part()
{
Name = part.Name
};
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}
}
Here's my controller.
[Route("api/[controller]")]
[ApiController]
public class PartsController : ControllerBase
{
private readonly IPartService _partService;
public PartsController(IPartService partService)
{
_partService = partService;
}
[HttpPost]
public async Task<ActionResult<Part>> CreatePart(PartVM part)
{
try
{
if (part == null)
return BadRequest();
var _part = new Part()
{
Name = part.Name
};
var createdPart = await _partService.CreatePart(_part);
return CreatedAtAction(nameof(GetPart),
new { id = createdPart.Id}, createdPart);
}
catch (Exception /*ex*/)
{
return StatusCode(StatusCodes.Status500InternalServerError, "Error creating new record in the database");
}
}
I'm getting a build error saying "CS1503 Argument 1: cannot convert from 'MusicManager.Shared.Part' to 'MusicManager.Server.Data.ViewModels.PartVM'".
It's refering to "_part" in this line "var createdPart = await _partService.CreatePart(_part);".
Any help is appreciated, thank you!
you have a CreatePart method which receives a PartVM model, but you are sending a Part Model to it
change your method to this :
public async Task<Part> CreatePart(Part part)
{
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}

Receive a jagged array in query parameters

I currently have a controller with an action that fetches some information, this action receives as a query param a jagged array to filter the information, example: [["Day", ">=", "01.01.2021"],["User", "=", "SomeUserId"]].
My current action declarion:
[HttpGet]
public async Task<object> Get(string[][] filters)
{
...
}
When I make an AJAX request from the client the URL goes encoded in the following way (DevTools request header parameters view):
filters[0][]: Day
filters[0][]: >=
filters[0][]: 01.07.2021
filters[1][]: User
filters[1][]: =
filters[1][]: SomeUserId
Url Encoded FYI: ...filters%5B0%5D%5B%5D=Day&filters%5B0%5D%5B%5D=%3E%3D&filters%5B0%5D%5B%5D=01.07.2021&filters%5B1%5D%5B%5D=User&filters%5B1%5D%5B%5D=%3D&filters%5B1%5D%5B%5D=SomeUserId
The problem
My action when receives the information above has the value of two empty string arrays string[2][]. The following image is a debug print screen from VS of the filters variable.
Should I serialize? Or use a different structure?
Here is a working demo:
View:
<button type="button" onclick="SendRequest()">Click</button>
#section Scripts
{
<script>
function SendRequest() {
var day = "Day";
var simble = encodeURIComponent(">=");
var date = "01.07.2021";
var user = "UserName";
var simble2 = "=";
var id = "1";
$.ajax({
//url: "api/values?filters[0][0]=Day&filters[0][1]=>=&filters[0][2]=01.07.2021&filters[1][0]=User&filters[1][1]==&filters[1][2]=2"
url: "api/values?filters[0][0]=" + day + "&filters[0][1]=" + simble + "&filters[0][2]=" + date + " &filters[1][0]=" + user + "&filters[1][1]=" + simble2 + "&filters[1][2]=" + id + "",
type: 'GET',
success: function (res) {
alert("success");
},
error: function () {
}
})
}
</script>
}
Controller:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
public void Get([FromQuery] string[][] filters)
{
}
}
One option is to wrap the input in a class like
public class InputRequest
{
public string Field { get; set; }
public string Operator { get; set; }
public string Value { get; set; }
}
Then use a custom model binder -
class InputRequestModelBinder : IModelBinder
{
static readonly JsonSerializerOptions options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(List<InputRequest>)) return Task.CompletedTask;
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var results = valueProviderResult.Select(t => JsonSerializer.Deserialize<InputRequest>(t, options)).ToList();
bindingContext.Result = ModelBindingResult.Success(results);
return Task.CompletedTask;
}
}
Lastly, hook the model binder to controller method -
[HttpGet]
[Route("show")]
public string Show([ModelBinder(typeof(InputRequestModelBinder))] List<InputRequest> req)
{
//do something
}
Example usage -
/SomeController/show?req=%7B%0A%20%20%22field%22%3A%20%22name%22%2C%0A%20%20%22operator%22%3A%20%22%3D%22%2C%0A%20%20%22value%22%3A%20%22tom%22%0A%7D&req=%7B%0A%20%20%22field%22%3A%20%22age%22%2C%0A%20%20%22operator%22%3A%20%22%3C%22%2C%0A%20%20%22value%22%3A%20%2220%22%0A%7D
Decoded url looks like this -
/SomeController/show?req={
"field": "name",
"operator": "=",
"value": "tom"
}&req={
"field": "age",
"operator": "<",
"value": "20"
}
Pro -
You get to explicitly state the contract to your API consumers about expected values in InputRequest
Con -
Your request query string length increases, so you may hit the limit soon. Although you may convert it to a POST method, but then it violates REST principles.

Getting "no serializer found for class" Exception in restAssured post request

I have a Json Payload for a Post call as below:
{
"action" : "Closed",
"Id" : 30144,
"expireDate" : null,
"inputUser" : "abc",
"previousStatusId" : 1,
"statusId" : 4,
"Notes" : [ ]
}
My POJO classes for the above payload is as below
public class UpdateNoteStatus {
private String action;
private int Id;
private String expireDate;
private String inputUser;
private int previousStatusId;
private int statusId;
private List<Notes> Notes;
public void setAction(String action) {
this.action = action;
}
public void setId(int Id) {
this.Id = Id;
}
public void setExpireDate(String expireDate) {
this.expireDate = expireDate;
}
public void setinputUser(String inputUser) {
this.inputUser = inputUser;
}
public void setPreviousStatusId(int previousStatusId) {
this.previousStatusId = previousStatusId;
}
public void setStatusId(int statusId) {
this.statusId = statusId;
}
public void setNotes(List<Notes> Notes) {
this.Notes = Notes;
}
}
public class Notes{
}
Now I have assigned the values in the main class from where I am making the API call is as below:
ArrayList<Notes> Notes = new ArrayList<Notes>();
UpdateNoteStatus objUpdateNoteStatus = new UpdateNoteStatus();
objUpdateNoteStatus.setAction("Closed");
objUpdateNoteStatus.setId(Integer.parseInt("30144"));
objUpdateNoteStatus.setinputUser("abc");
objUpdateNoteStatus.setPreviousStatusId(1);
objUpdateNoteStatus.setStatusId(4);
objUpdateNoteStatus.setNotes(Notes);
But when I am making the API POST call it is throwing exception - "no serializer found for class and no properties discovered to create beanserializer". Could you please help. The Step is hightlighted in Bold.
RequestSpecification rs = given().contentType("application/json");
**rs = rs.body(objUpdateNoteStatus);** //In This Step I am getting the above mentioned Exception
Response res = rs.when().post("/UpdateStatus");
as you are initializing an empty object , you need to use below Annotation supported in below library
com.jayway.restassured.RestAssured;
#JsonIgnoreProperties(ignoreUnknown=true)
class UpdateNoteStatus

How to return extra message while return type is T?

I have a function:
public async Task<T> PostAsync<T>(string url,string parameters)
{
var response=await httpClient.PostAsync(url,data);
if(response is null)
{
return default;
}
}
if response is null I can only return default. now I want to add extra message to T that "response is null"
how to do it?
If you want to return an object and a message, you would be better off creating a ResponseObject DTO to take both of those as parameters. That way you can add extra information to return if you want like error codes or other data.
Something like:
public class ResponseDTO<T>
{
public T Object { get; set; }
public string Message { get; set; }
}
public async Task<ResponseDTO<T>> PostAsync<T>(string url,string parameters)
{
var response=await httpClient.PostAsync(url,data);
if(response is null)
{
return new ResponseDTO<T> {
Object = default(T),
Message = "Response is null"
};
}
return new ResponseDTO<T> {
Object = response
};
}

How to Post the below request using RestAssured in selenium

How to POST the below request using RestAssured in selenium.
The request is as follows:
{
"ShipmentID": "",
"ShipmentNumber": "123455-6",
"Comments": "",
"LineIDs": [
{
"ShipmentDID": "",
"AssetNum": "759585",
"FileC": "",
"SerialN": "",
"LineID": "5",
"Status": "Accept",
"TransferCancelComment": ""
}
Below is the code I have used but not sure how should i continue for the "LineID's" as it has few more attributes in it.
#Test
public void TransferIn() {
RestAssured.baseURI="testurl.rest.com";
RequestSpecification httpRequest = RestAssured.given();
JSONObject requestparams=new JSONObject();
try {
requestparams.put("ShipmentID", "");
requestparams.put("ShipmentNumber", "123455-6");
requestparams.put("Comments", "");
requestparams.put("LineIDs", "");
}
Hope below code will solve your problem.
#Test
public void TransferIn() {
RestAssured.baseURI="testurl.rest.com";
RequestSpecification httpRequest = RestAssured.given();
JSONObject requestparams = new JSONObject();
JSONArray lineIdsArray = new JSONArray();
JSONObject lineIdObject = new JSONObject();
try {
requestparams.put("ShipmentID", "");
requestparams.put("ShipmentNumber", "123455-6");
requestparams.put("Comments", "");
lineIdObject.put("ShipmentDID", "");
lineIdObject.put("AssetNum", "759585");
lineIdObject.put("FileC", "");
lineIdObject.put("SerialN", "");
lineIdObject.put("LineID", "5");
lineIdObject.put("Status", "Accept");
lineIdObject.put("TransferCancelComment", "");
lineIdsArray.put(lineIdObject);
requestparams.put("LineIDs", lineIdsArray);
} catch (JSONException e) {
}
System.out.println(requestparams);
}
A better approach could be, construct the json from a POJO/model file and then pass that to the test. By this, there is clear separation of the intent and in future if you want to verify any response of that type, you can simply de-serialize and get the values using getters of the POJO.
e.g if your json is
{
"name":"Mohan",
"age":21
}
Your POJO would look something like below:
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("name")
#Expose
private String name;
#SerializedName("age")
#Expose
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
I am using GSON from google which is serialization and de-serialization library. Construct your payload using your POJO and pass that as an argument to your test method.
This will make your code more readable, maintainable, scalable ....
The idea behind this was the intent of test should not be polluted and there will be clear separation between the responsibilities of different entities.