How to create web api methods? - json

Hi I am developing one restfull wep api application. I am new to the world of web api and little confused about http verbs. My tasks is to write services using web api2. I have one table in sql server and i am trying to do basic crud operation around this table. I want to send data in json format and return data as json. For example http://localhost:26079/api/User_Creation/1 returns data in json format as expected. My task is to host above method in iis so that anyone can access that method to retrieve data. I am confused suppose if i want to insert some data to db then what would be the method? I have below code in controllera and i am able to insert data.
public void Post(Noor_Users users)
{
if (ModelState.IsValid)
{
entityObject.Noor_Users.Add(users);
int result = entityObject.SaveChanges();
}
}
When i insert data my url will be http://localhost:26079/ but how can i expose my insert data method to outside world? My requirement is as follows.
URL:/user_creation
method:post
Request:parameters such as fname,lname as json
Response:0 for success 1 for failure and data(unique id assigned to each user)
may i get some help on this? Thank for consideration.

When considering REST it is important to understand and design it as you are taking actions against a resource at the location, and not like making a remote function call.
So I would suggest to have API as -
http://localhost:26079/api/User
instead of - http://localhost:26079/api/User_Creation
In order to adhere to REST principals.
Doing this I am very clearly stating that the user of the api will be able to perform operations on the resource (which is a User in this case) using different verbs viz. GET, POST, PUT and DELETE.
See some examples on using the API -
If I need to get a user with Id 1, I would call api like, http://localhost:26079/api/User/1 with GET request
To create a new user, I would call, http://localhost:26079/api/User with POST request and send the user information in request body
To delete a user with id 1, I would call http://localhost:26079/api/User/1 with Delete request
To update a user data with Id 1, call http://localhost:26079/api/User/1 with PUT request and send the updated user information in request body
Please note here that we are using just a single endpoint to perform different operations on our User by changing different HTTP verbs.
The default asp.net web api template gives some good hint on how to declare different verb methods e.g. -
public class UserController : ApiController
{
// GET api/<controller>/1
public User Get(int id)
{
}
// POST api/<controller>
public void Post([FromBody]User user)
{
}
// PUT api/<controller>/1
public void Put(int id, [FromBody]User user)
{
}
// DELETE api/<controller>/1
public void Delete(int id)
{
}
}
There is some good information here and here on designing restful api.

If you want to call your emthod from Angular, you can just use $http.post() method:
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
Here you can find more information.

Related

HTTP POST-ing both JSON data, and query string values to a web API in dotNet core 3.0

Background:
I'm trying to implement a web API using dotNet core 3.0 so that it would accept a POST-ed payload of JSON data.
I have achieved this, but there is an additional complexity: The system that posts the JSON data provides authentication via an API key which appears on the query string. (Actually - it provides 3 query string values: the api key, a timestamp, and a MAC hash, based on a shared secret, of the first two values.)
(I would rather it appeared in the HTTP header as an X-Api-Key value, as I have implemented security via this method previously - but I don't get a choice)
The JSON data is actually a list of objects of the same type, so the binding on the controller method looks like this:
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult AddMyStuffBatches(List<MyStuffBatch> batches)
The authentication values that appear on the query string are really nothing to do with the model - they are unrelated to the data uploaded by the process. So as such, they should not appear in the batches list or as a property of a specific instance of MyStuffBatch.
So the question is: How do I design a controller that deals with the authentication API key details passed on the query string, whilst (assuming a valid API key etc. is passed) still processing the JSON payload as before?
You could use [FromQuery] on your post action to bind parameters from query string, for example:
Url:
POST https://localhost:5001/weatherforecast?timestamp=2019-11-06T09:27:36.000Z&apiKey=secretkey
Action:
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult AddMyStuffBatches(List<MyStuffBatch> batches,[FromQuery] string timestamp, [FromQuery] string apiKey)

Calling an API HttpGet Action from Angular with a large amount of search criteria throws a CORS policy error

I have a Core 2.2 Web API project as my back-end for an Angular front-end. On one screen I allow the user to select x amount of records for processing from a data grid. Before the records can be processed I need to check the database to see if records exist in another table by passing a list of 3 fields (intelligent key) to my API. I put this list into an object array, do a Json.stringify on that object and send it to my API as a Get request. This works fine as long as I select 1-3 records. As soon as I select 4 or more records I get "Access to XMLHttpRequest at 'request url' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
My Cors policy indicates it should let anything through and I'm also confused by why 1-3 records works fine.
In my startup.cs -> ConfigureServices method I have the Cors policy defined like so:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
In my Angular service I make this call which serializes by array (apiUrl is my url to call my API: https://localhost/api/controller)
getRecordsByIntelligentKey(intelligentKey: IntelligentKey[]): Observable<Record[]>{
const jsonObject = JSON.stringify(intelligentKey);
const url = `${apiUrl}/${jsonObject}`;
return this.http.get<Record[]>(url).pipe(
tap(_ => console.log('fetching records based on intelligent key')),
catchError(this.handleError('getRecordsByIntelligentKey', []))
);
}
In my controller GET action I deserialize my string. I mean I'd like to pass an object but I think I need to do a POST for that.
[HttpGet("{jsonObject}")]
public ActionResult<List<Commission>> GetByCustomerAndTerritoryManager(string jsonObject)
{
try
{
var intelligentKey = JsonConvert
.DeserializeObject<List<ThreeFields>>(jsonObject);
return _repo.GetRecordsByIntelligentKey(intelligentKey);
}
catch (Exception ex)
{
_logger.Error(ex, "Error retrieving records.");
throw;
}
}
Now my problem is the user could select 1000s of records. When I select over 1000 records I just get ERR_CONNECTION_RESET probably due to the querystring being way too long.
I'm thinking I need an object but everything I've researched seems to advise against doing that with a GET and using the POST request instead. Problem is, it's a restful API and I'm already using the POST request for the processing portion. I guess I could use PUT or DELETE but it just feels wrong. I'm going to wire up the PUT right after I post this question to see if it will work but ultimately I'd like to find the correct solution for this.
UPDATE: The PUT method works fine even with over 1000 records selected so I guess this will be my interim solution for now. I still feel like there's code smell and would love to use a GET but at least this allows me to proceed.

Spring RESTful service returning JSON from another service

I have been creating Spring RESTful services for a while and typically I am building my own services so I create domain objects and populate them and the framework takes care of the conversion to JSON.
I have a situation now where I simply need my service to act as a pass through to another system's service that is already RESTful and returns JSON.
URL https://:/service/serviceInfo
Method GET
HTTP Content Type Produces: application/json
I simply want to wrap this call (I will apply some security checks on the service) and pass that JSON returned straight back to my service without mapping it back to Java objects, only to return as JSON to the client. Is there a simple way to do this, with minimal code?
Thanks in advance.
Can you see if this works for you?
#RequestMapping("/child")
public String testMethod(#RequestParam String param) {
return new RestTemplate().exchange("https://api.twitter.com/1/statuses/user_timeline.json", HttpMethod.GET, null, String.class).getBody();
}
You just replace the url for your own. I can also guide you to using the RestTemplate with POST or DELETE requests etc. if you need. Also adding parameters or headers if you need. I've used it extensively in some projects.

Other technologies that can perform DTO request response like WCF

I have a WCF service that allows me make a request using an DTO and replies with a DTO for a WPF application. For example I pass a filter object for products which has a few properties for things I want to filter on and a couple of extras for paging, (the server will take care processing the filter object and getting the data) an example is like this.
public async Task<ObservableCollection<ProductListItem>> GetProductList(ProductFilter filter, int startIndex, int pageSize, string sortBy)
I am wondering if there exists any other technologies beside WCF that allow such an operation, From my preliminary research which may be quite off is that WebAPI uses the GET, POST, PUT verbs and routing rules which is quite different.
ServiceStack looks like it might be able to do this I can see on slide 37 at https://servicestack.net/features
it says.
List<Product> productOver2Bucks = client.Get(new FindProducts{PriceGreaterThan = 2})
Which seems pretty close but might still require Rest verbs as it uses a Get().
I don't know it it is FUD or not but I have been reading that soap over WCF is believed by some to be a legacy technology and JSON is the way of the future. So is there a replacement technology that will work with a method signature to the one I have above? That i could call from platforms such as Windows universal applications.
In ServiceStack if you design your Service with the Any method name, e.g
public object Any(Request request)
{
return new Response { ... };
}
This will allow calling this Service from Any HTTP Verb on any Format or endpoint (e.g. JSON, XML, MsgPack, Protocol Buffers, SOAP, Message Queue's, etc).
Also you don't need to define any [Route] for your Request DTO's since it will automatically fallback into using the pre-defined Routes when none are available.
public class Request : IReturn<Response> { ... }
public class Response { }
So with the above Service you can use ServiceStack .NET ServiceClients to call the API's using any verb, e.g:
var client = new JsonServiceClient(baseUrl);
Response response = client.Get(new Request { ... });
Response response = client.Post(new Request { ... });
When preferred you can also use the async API's, e.g:
var response = await client.GetAsync(new Request { ... });
var response = await client.PostAsync(new Request { ... });
Which if you don't care for using verbs you can use the generic Send API, e.g:
Response response = client.Send(new Request { ... });
Which just uses POST underneath, although it's highly recommended to use Get for "read only" queries as it will allow the Services HTTP responses to be cached by any intermediate HTTP Middleware or proxies.
Add ServiceStack Reference
Also if you're coming from WCF you'll also enjoy ServiceStack's, Add ServiceStack Reference which provides a number of advantages over WCF's Add Service Reference feature but still provides the same utility in being able to generate a typed API from a remote url for:
C# Add Reference
F# Add Reference
VB.NET Add Reference
TypeScript Add Reference
With more languages to follow.
Advantages over SOAP
Whilst ServiceStack still enables WSDL's, XSD's for your Services so they can be called from SOAP 1.1/1.2 endpoints for legacy compatible reasons - there are a number of reasons why using clean HTTP and JSON/XML API's are preferred.

General pattern for WCF/Web API request and response messages structure

We have a Web API service of our own which in turn calls the third party WCF web service.
I'm trying to come up with a pattern where we get a response from WCF within which there will be response.status and response.errorDescription. Based on these properties we will translate in to user friendly error messages. This message then will need to be passed on to client via Web API or Controller/Action.
Wondering if there is already a pattern to pass response status and message to client.
Also should all WCF web service must return the response status so that client can look at this status first and process the data? What's the best practice pattern here?
Thanks.
If you have control over third party WCF their contract will need to be adjusted to send response the way you want it.
We have got many services running which has the same pattern. To our clients we expose the contracts like this.
..............................................
[OperationContract]
ResponseType GetData (string request)
..............................................
[DataContract]
public class ResponseType
{
[DataMember]
public string Status {get;set;}
public string ErrorDescription {get;set;}
}
now when clients get the response, they can look for status and ErrorDescription.
This is one pattern which is mostly recommended.
There is another way you can do it which is not recommended and is complex. That is by creating a WCF Extension that intercepts the response and converts to a meaningful result.