Uncaught error in Braintree hosted fields solution - javascript

I am implementing a hosted field Braintree-solution and I am following the documentation very exactly. And the documentation is pretty awesome I must say. Still, I get an uncaught reference error when loading the client. The error appears at the client token. Even though it is set I get an uncaught reference-error there.
Here is the end of the razor-page where the problem occurs:
var form = document.querySelector('#my-sample-form');
var submit = document.querySelector('input[type="submit"]');
var clientToken = #ViewBag.ClientToken;
braintree.client.create({
authorization: clientToken
}, function (err, clientInstance) {
if (err) {
console.error(err);
return;
}
Here are the methods in the controller (even though I think that is not what generates the problem). Redirected from the post-method which picks up the billing information:
return RedirectToAction(nameof(Pay));
}
else
{
return View(order);
}
}
public ActionResult Pay()
{
var gateway = GetGetAway();
string clientToken = gateway.ClientToken.Generate();
ViewBag.ClientToken = clientToken;
return View();
}
public BraintreeGateway GetGetAway()
{
return new BraintreeGateway
{
Environment = Braintree.Environment.SANDBOX,
MerchantId = "xxxxxxx",
PublicKey = "xxxxxxxx",
PrivateKey = "xxxxxxxxxx"
};
}
[HttpPost]
public ActionResult CreatePurchase()
{
var gateway = config.GetGateway();
var request = new TransactionRequest
{
Amount = 15,
PaymentMethodNonce = Request.Query["payment_method_nonce"],
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};
Result<Transaction> result = gateway.Transaction.Sale(request);
if (result.IsSuccess())
{
Transaction transaction = result.Target;
return View("Completed");
}
else
{
return RedirectToAction("Unsuccessful");
}
}

Related

Dotnet core webapi returns 401 Unauthorized with JWT authentication

I am using HTML/Javascript in VS Code and using Dot net core 3.1 in Visual Studio 2019 for Web API development. Also using IIS on Windows 10 professional to test the API.
Developed login page with following code. Once user enters userid and password, clicks on login button, a web api "TestAuthService" is invoked.
function fnlogin() {
const uname = document.getElementById('uname').value;
const pwd = document.getElementById('pwd').value;
const logindata = {
username: uname,
password: pwd
}
const loginurl = 'http://localhost:8091/api/Auth/Login';
authenticate(loginurl, logindata);
}
async function authenticate(loginurl, logindata) {
console.log(logindata)
const response = await fetch(loginurl , {
method: "POST",
mode: "cors",
body: JSON.stringify(logindata),
headers: { "Content-type" : "application/json, charset=UTF-8"}
});
const rdata = await response.json();
console.log(rdata);
if (!rdata.success) {
document.getElementById("loginMessage").innerHTML = rdata.message;
return;
}
const inMemoryToken = rdata.data
localStorage.setItem('user', JSON.stringify(rdata));
window.location.href = "http://127.0.0.1:5500/Weatherinfo.html";
}
The API TestAuthService is published in IIS on localhost:8091. On successful login, a JWT is returned to the javascript. This works properly. The JWT is stored in localStorage in chrome browser by Javascript.
The auth controller code is as follows :
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IAuthRepository _authRepo;
public AuthController(IAuthRepository authRepo)
{
_authRepo = authRepo;
}
[HttpPost("Register")]
public async Task<ActionResult<ServiceResponse<int>>> Register(UserRegisterDto request)
{
var response = await _authRepo.Register(
new User { Username = request.Username }, request.Password
);
if (!response.Success)
{
return BadRequest(response);
}
return Ok(response);
}
[HttpPost("Login")]
public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
{
var response = await _authRepo.Login(
request.Username, request.Password
);
if (!response.Success)
{
return BadRequest(response);
}
return Ok(response);
}
The AuthRepository code is as follows :
public class AuthRepository : IAuthRepository
{
private readonly AppDbContext _context;
private readonly IConfiguration _configuration;
public AuthRepository(AppDbContext context, IConfiguration configuration)
{
_configuration = configuration;
_context = context;
}
public async Task<ServiceResponse<string>> Login(string username, string password)
{
var response = new ServiceResponse<string>();
var user = await _context.Users.FirstOrDefaultAsync(x => x.Username.ToLower().Equals(username.ToLower()));
if (user == null)
{
response.Success = false;
response.Message = "User not found.";
}
else if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
{
response.Success = false;
response.Message = "Wrong password.";
}
else
{
response.Data = CreateToken(user);
}
return response;
}
public async Task<ServiceResponse<User>> Register(User user, string password)
{
ServiceResponse<User> response = new ServiceResponse<User>();
if (await UserExists(user.Username))
{
response.Success = false;
response.Message = "User already exists.";
return response;
}
CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
_context.Users.Add(user);
await _context.SaveChangesAsync();
response.Data = user;
return response;
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username.ToLower().Equals(username.ToLower())))
{
return true;
}
return false;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != passwordHash[i])
{
return false;
}
}
return true;
}
}
private string CreateToken(User user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username)
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("AppSettings:Token").Value));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
var tokendDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = System.DateTime.Now.AddDays(1),
SigningCredentials = creds
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokendDescriptor);
return tokenHandler.WriteToken(token);
}
If the login is successful, the page Weatherinfo.html is displayed, This page has button "Get Weather data" , which when clicked, invokes another web api "weatherforecast"
<button type="button" onclick="return getWeather();">Get Weather data</button>
<table id="weatherdata">
<thead>
</thead>
<tbody id="weatherdatalist">
</tbody>
</table>
<script>
async function getWeather() {
const url = 'http://localhost:5861/weatherforecast';
const localstorage_user = JSON.parse(localStorage.getItem('user'));
const inMemToken = localstorage_user.data
console.log(inMemToken)
/*
const response = await fetch(url);
*/
const response = await fetch(url, {
headers: {
Authorization: 'Bearer ${inMemToken}'
}
});
const data = await response.json();
console.log(data)
display(data);
}
function display(data) {
let tab = "";
data.forEach(element => {
tab += `<tr>
<td > ${element.date} </td>
<td> ${element.temperatureC} </td>
<td> ${element.temperatureF} </td>
<td> ${element.summary} </td>
</tr>`;
});
document.getElementById("weatherdatalist").innerHTML = tab;
}
</script>
The weatherforecast api has following code
Startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("AllowOrigins", builder =>
{
builder.WithOrigins("http://localhost:5500", "http://127.0.0.1:5500")
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = false,
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseRouting();
app.UseCors("AllowOrigins");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
The controller is as follows
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
The issue is the weatherforcast api fails with HTTP error 401 (Unauthorized)
I am not sure if I am passing the JWT correctly in the code below
const response = await fetch(url, {
headers: {
Authorization: 'Bearer ${inMemToken}'
}
});
The issue seems to be resolved now.
Corrected the fetch api call as
const response = await fetch(url, {
headers: {
"Authorization": `Bearer ${inMemToken}`
}
});
``

Authorization Web Asp.Net Core JWT , Angular 8

can some please point where the issue is.
the problem that i encounter is i have a controller that i added an attribute Authorize. So, when i try to access the actionResult GETDATA it says unable to find the action. but if remove the attribute Authorize, it's working as expected.
So everytime i make a request i add a jwt token on the header.
Here are codes:
**Angular 8 HttpInterceptor**
const currentUser = this.authenticationService.currentUserValue;
//if (currentUser && currentUser.authData) {
if (currentUser && currentUser.Token) {
debugger;
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentUser.Token}`,
CurrentTabID: `${currentUser.CurrentTabID}`
}
});
}
**MyController**
[Authorize]
[ApiController]
[Route("[controller]")]
public class PatientController : ControllerBase
{
[HttpGet("GetTestData")]
//--These is the one i can't access
public IActionResult GetTestData()
{
return Ok("");
}
[AllowAnonymous]
[HttpGet("GetTestDataOne")]
public IActionResult GetTestDataOne()
{
return Ok("Hi John");
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=.; Database=blah;persist security info=True;user id=blah;password=blah;"
},
"AllowedHosts": "*",
"ApplicationSettings": {
"Secret": "1234567890123456",
"ClientURL": ""
}
}
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<PPMPBookingContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:Secret"].ToString());
// configure strongly typed settings objects
//var appSettingsSection = Configuration.GetSection("AppSettings");
//services.Configure<AppSettings>(appSettingsSection);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer="vlad",
ValidAudience="Client"
};
});
// configure DI for application services
services.AddScoped<IUserService, UserService>();
services.AddScoped<IPracticeService, PracticeService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
AccountController
public UserInfo Authenticate(int businessID, string username, string password)
{
// authentication successful so generate jwt token
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_config.GetSection("ApplicationSettings:Secret").Value);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.ID.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
userInfo.Token = tokenHandler.WriteToken(token);
byte[] bytes = Encoding.GetEncoding(28591).GetBytes($"{businessID}{username}");
userInfo.AuthData = System.Convert.ToBase64String(bytes);
user.Password = null;
userInfo.User = user;
userInfo.BusinessID = businessID;
userInfo.Practice = _practiceService.PracticeInfo(businessID);
userInfo.CurrentTabID = Guid.NewGuid().ToString();
return userInfo;
}

Using Graph API not able to get events for particular date using filter param

var authEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?";
var redirectUri = "http://localhost:8080";
var appId = "SomethingSomething";
var scopes = "openid profile User.Read Mail.Read Calendars.Read";
function getUserEvents(callback) {
getAccessToken(function(accessToken) {
if (accessToken) {
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, accessToken);
}
});
// Get the 10 newest events
client
.api("/me/events")
.filter("startDateTime='2018-03-01'&endDateTime='2018-03-31'")
.select("subject,start,end,createdDateTime")
.orderby("createdDateTime DESC")
.get((err, res) => {
if (err) {
callback(null, err);
} else {
callback(res.value);
}
});
} else {
var error = { responseText: "Could not retrieve access token" };
callback(null, error);
}
});
}
This is the request that my program sends out:
https://graph.microsoft.com/v1.0/me/events?$filter=2018-07-15T01:00:00&$select=subject,start,end,createdDateTime&$orderby=createdDateTime%20DESC
400 (Bad Request)
You're attempting to filter the /events endpoint using properties that don't exist in the event object (startDateTime and endDateTime). You're also passing a = in the filter clause instead of eq.
The /calendarView endpoint does have startDateTime and endDateTime parameters, but these are query params unto themselves (not part of a filter clause). I suspect this is the operation you're actually looking for:
client
.api("/me/calendarview")
.query({
startdatetime: "2018-03-01T00:00:00.0000000",
enddatetime: "2018-03-31T23:00:00.0000000"
})
.select("subject,start,end,createdDateTime")
.orderby("createdDateTime DESC")
.get((err, res) => {
if (err) {
callback(null, err);
} else {
callback(res.value);
}
});

Azure: Cannot call method 'then' of undefined at exports.post

I am using azure mobile services, with following custom API:
var returnVal = new Object;
exports.post = function (request, response) {
// Use "request.service" to access features of your mobile service, e.g.:
// var tables = request.service.tables;
// var push = request.service.push;
var merchantdetailsTable = request.service.tables.getTable("merchantdetails");
var resourceName;
//console.log(JSON.stringify(request.parameters));
merchantdetailsTable.insert({
name: request.body.workerNameInput,
emailid: request.body.workerEmailIDInput,
contact: request.body.workerContactNumberInput
}).then(function (merchantInserted) {
returnVal.workerId = merchantInserted.id;
resourceName = returnVal.workerId.toLowerCase();
var shopworkersTable = request.service.tables.getTable("shopworkers");
return shopworkersTable.insert({
id: merchantInserted.id,
shopid: request.body.shopId
});
}, function(err){
return response.send(statusCodes.INTERNAL_SERVER_ERROR, err);
}).then(function () {
var accountName = appSettings.STORAGE_ACCOUNT_NAME;
var accountKey = appSettings.STORAGE_ACCOUNT_ACCESS_KEY;
var host = accountName + '.blob.core.windows.net';
var blobService = azure.createBlobService(accountName, accountKey, host);
return blobService.createContainerIfNotExists("merchant-image", { publicAccessLevel: 'blob' });
}, function (err) {
return response.send(statusCodes.INTERNAL_SERVER_ERROR, err);
}).then(function(error){
if (!error) {
// Provide write access to the container for the next 5 mins.
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Expiry: new Date(new Date().getTime() + 5 * 60 * 1000)
}
};
// Generate the upload URL with SAS for the new image.
var sasQueryUrl =
blobService.generateSharedAccessSignature("merchant-image",
'', sharedAccessPolicy);
// Set the query string.
returnVal["merchantImage"].sasQueryString = qs.stringify(sasQueryUrl.queryString);
// Set the full path on the new new item,
// which is used for data binding on the client.
returnVal["merchantImage"].imageUri = sasQueryUrl.baseUrl + sasQueryUrl.path + '/'
+ resourceName;
var accountName = appSettings.STORAGE_ACCOUNT_NAME;
var accountKey = appSettings.STORAGE_ACCOUNT_ACCESS_KEY;
var host = accountName + '.blob.core.windows.net';
var blobService = azure.createBlobService(accountName, accountKey, host);
return blobService.createContainerIfNotExists("pharmacy-certificate", { publicAccessLevel: 'blob' });
}
else {
return response.send(statusCodes.INTERNAL_SERVER_ERROR);
}
}, function (err) {
return response.send(statusCodes.INTERNAL_SERVER_ERROR, err);
}).done(function (error) {
if (!error) {
// Provide write access to the container for the next 5 mins.
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Expiry: new Date(new Date().getTime() + 5 * 60 * 1000)
}
};
// Generate the upload URL with SAS for the new image.
var sasQueryUrl =
blobService.generateSharedAccessSignature("pharmacy-certificate",
'', sharedAccessPolicy);
// Set the query string.
returnVal["pharmacyCertificate"].sasQueryString = qs.stringify(sasQueryUrl.queryString);
// Set the full path on the new new item,
// which is used for data binding on the client.
returnVal["pharmacyCertificate"].imageUri = sasQueryUrl.baseUrl + sasQueryUrl.path + '/'
+ resourceName;
response.send(statusCodes.OK, returnVal);
}
else {
return response.send(statusCodes.INTERNAL_SERVER_ERROR);
}
}, function (err) {
return response.send(statusCodes.INTERNAL_SERVER_ERROR, err);
});
response.send(statusCodes.OK, { message : 'Hello World!' });
};
exports.get = function(request, response) {
response.send(statusCodes.OK, { message : 'Hello World!' });
};
I am getting following error:
TypeError: Cannot call method 'then' of undefined
at exports.post (D:\home\site\wwwroot\App_Data\config\scripts\api\addWorker.js:17:8)
Azure Mobile Services does not return promises from table operations. You need to pass an options object that contains success and error callbacks, as described at https://msdn.microsoft.com/en-us/library/azure/jj554210.aspx.
I highly recommend that you take a look at the newer implementation of the product, Azure Mobile Apps - https://www.npmjs.com/package/azure-mobile-apps. (Disclaimer: I work for Microsoft on the Azure Mobile Apps team)

Thinking OOP in JavaScript / Node.js

I understand well the concepts of OOP and prototypal inheritance in JavaScript, but sometimes, I wonder how to make use of these in real world applications.
I'll take as an exemple a simple(istic) contact management web application I pushed on GitHub a couple of months ago.
In the main handler mainly reside functions:
var UserModel = require('../models/userModel.js');
var checkObjectId = new RegExp('^[0-9a-fA-F]{24}$');
var root;
exports.getContacts = function(request, response) {
var id = JSON.parse(request.params.user)[0];
// validate
if (!checkObjectId.test(id)) {
return res.status(400).json({error: 'Not a user id'});
}
UserModel.findById(id, function(err, user) {
if (err) {
return console.log(err);
}
response.send(user.contacts);
});
};
exports.addContact = function(request, response) {
var id = JSON.parse(request.params.user)[0];
// validate
if (!checkObjectId.test(id)) {
return res.status(400).json({error: 'Not a user id'});
}
UserModel.findById(id, function(err, user) {
if (err) {
return console.error(err);
}
var contact = {};
// avoid to save empty info
if (request.body.first.length > 1) {contact.first = request.body.first;}
if (request.body.last.length > 1) {contact.last = request.body.last;}
if (request.body.mobile.length > 1) {contact.mobile = request.body.mobile;}
if (request.body.home.length > 1) {contact.home = request.body.home;}
if (request.body.office.length > 1) {contact.office = request.body.office;}
if (request.body.email.length > 1) {contact.email = request.body.email;}
if (request.body.company.length > 1) {contact.company = request.body.company;}
if (request.body.description.length > 1) {contact.description = request.body.description;}
if (request.body.keywords.length > 1) {contact.keywords = request.body.keywords;}
user.contacts.push(contact);
user.save(function(err) {
if (err) {
return console.error(err);
}
console.log('contact saved');
response.send(user.contacts);
});
});
};
exports.updateContact = function(request, response) {
var id = JSON.parse(request.params.user)[0];
// validate
if (!checkObjectId.test(id)) {
return res.status(400).json({error: 'Not a user id'});
}
var contact = {
_id: request.body._id,
first: request.body.first,
last: request.body.last,
mobile: request.body.mobile,
home: request.body.home,
office: request.body.office,
email: request.body.email,
company: request.body.company,
description: request.body.description,
keywords: request.body.keywords
};
UserModel.update({_id: id, "contacts._id": request.body._id}, {$set: {"contacts.$": contact}}, function(err, user) {
if (err) {
return console.error(err);
}
response.sendStatus(user);
});
};
exports.deleteContact = function(request, response) {
var id = JSON.parse(request.params.user)[0];
// validate
if (!checkObjectId.test(id)) {
return res.status(400).json({error: 'Not a user id'});
}
return UserModel.update({_id: id}, {$pull: {contacts: {_id: request.params.id}}}, function(err, user) {
if (err) {
return console.error(err);
}
console.log('contact removed');
console.log(user);
response.sendStatus(user);
});
};
It doesn't do much: fetch data from DB and return them or take data from user and save them to DB.
If it was a bit more complexe, I would surely place some logic in separate functions to reuse them and break down complexity.
Nevertheless, this code looks rather procedural, so does the hypothetical more complex version with separate functions. How would it be organized in a OOP way and how would I gain from it?
For instance, would I benefit from a User constructor?
I think the first thing you could do is nest the instance of your constructor inside an initializing function so you wouldn't have to repeat your validation code.
var connection = (function() {
var UserModel = require('../models/userModel.js');
var notAUser = {error: 'Not a user id'};
function init(request, response) {
var status = validate(JSON.parse(request.params.user)[0]);
if (!status.id) return response.status(400).json(status);
return new Connect(request, response, status.id);
}
function Connect(request, response, id) {
this.request = request;
this.response = response;
this.id = id;
this.info = { _id: id, "contacts._id": request.body._id };
}
function validate(id) {
if (!/^[0-9a-fA-F]{24}$/.test(id)) return notAUser;
else return {id: id};
}
Connect.prototype.getContact = function() {}
//etc...
return init;
})();
module.exports = connection;
Then in your actual application
var connection = require("./connection.js");
someAsync(data, function(req, res) {
var query = connection(req, res); //returned instance of constructor
query.getContact(someData, callback);
});
I would start by encapsulating the request and response since every method needs those. Like:
var contact = function (request, response) {
return {
add: add
}
function add() {
// add() gets access request and response for free
}
};
OR, if you are keen on the new operator:
function Contact(request, response) {
this.request = request;
this.response = response;
}
Contact.prototype.add = function () {
this.request;
}
Then move repeated code and callbacks to private methods you can reuse inside the object.

Categories

Resources