Варианты предпечатной подготовки Swagger AJAX
Код ниже это то, что я бегу. Полегче на меня для стиля кода... Я новичок: p
Я просто пытаюсь сделать запрос AJAX GET с HTML-страницы на одном сервере на мой API на втором сервере. Я уже поднялся на гору CORS и победил (то есть изначально получал ошибки CORS, но решил эту проблему). Теперь я получаю исключение ниже. Итак, вот большой вопрос:
Как правильно определить глобальный обработчик OPTIONS, используя Swagger для правильного ответа на запрос Ajax Preflight?
В качестве альтернативы, если я весь Нуб... пожалуйста, объясните мне, что я делаю неправильно. Я действительно ценю поддержку здесь... это поставило меня в тупик.
Для отсечения "Вы должны запустить HTML и Node на одном сервере". ответ... Для правильного масштабирования и обеспечения безопасности вы должны запускать свой API отдельно от внешнего интерфейса. В моем случае интерфейсом будет полнофункциональное веб-приложение и API, используемый для отделения визуального творчества от инженерного блеска.:)
Вот сценарий...
Клиент: ЛЮБОЙ веб-сервер: Apache на Amazon Linux AMI с использованием jQuery 1.6.2. Содержимое: простая html-страница с формой, использующей ajax для создания GET или POST, вызова моего API API-сервера: Amazon Linux AMI с Node Swagger Express (обновлен до текущий) Поведение: перейдите на страницу HTML Нажмите кнопку "Отправить". На консоль выводится исключение
Исключение:
Error: Path [/ping] defined in Swagger, but OPTIONS operation is not.
at middleware (/var/node/api/node_modules/swagger-express-mw/node_modules/swagger-node-runner/lib/connect_middleware.js:31:21)
at Layer.handle [as handle_request] (/var/node/api/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/var/node/api/node_modules/express/lib/router/index.js:302:13)
at /var/node/api/node_modules/express/lib/router/index.js:270:7
at Function.proto.process_params (/var/node/api/node_modules/express/lib/router/index.js:321:12)
at next (/var/node/api/node_modules/express/lib/router/index.js:261:10)
at /var/node/api/app.js:38:8
at Layer.handle [as handle_request] (/var/node/api/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/var/node/api/node_modules/express/lib/router/index.js:302:13)
at /var/node/api/node_modules/express/lib/router/index.js:270:7
Результат (возвращаемый почтальоном):
{
"result": "pong"
}
Заголовки (как возвращено Почтальоном):
Access-Control-Allow-Credentials → true
Access-Control-Allow-Headers → X-Requested-With,content-type
Access-Control-Allow-Methods → GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin → *
Connection → keep-alive
Content-Length → 17
Content-Type → application/json; charset=utf-8
Date → Tue, 01 Dec 2015 08:09:03 GMT
ETag → W/"11-df5e0e4c"
X-Powered-By → Express
Примечание. API не возвращает ответ из-за исключительной ситуации.
Код веб-страницы:
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Rusty Chapin">
<meta name="description" content="Sample execution of API to create new contact">
<title>Create New Contact</title>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.min.js"></script>
<script>
$(document).ready(function(){
var getResults = function(){
var contactemail = $('#contactemail').val();
var contactname = $('#contactname').val();
$.ajax({
type:"POST",
url: "http://xxx.xxx.xxx.xxx:10010/contact",
dataType: 'json',
contentType: 'application/json',
data: { contactemail: contactemail, contactname: contactname },
success: function(response){
$('#results').html('<h2 class="loading">Contact ID: ' +
response[0].contactid + '<br>Contact Email: ' +
response[0].contactemail + '<br>Contact Name: ' +
response[0].contactname + '<h2 />');
},
error: function(response){
$('#results').html('<h2 class="loading">Response: ' +
response + '<h2 />');
}
});
};
$('#submit').click(getResults);
});
</script>
</head>
<body>
<div class="container">
<header>
<h1>Create New Contact</h1>
</header>
<form>
<input type="email" placeholder="Email Address" id="contactemail" />
<input type="text" placeholder="Name" id="contactname" />
<button id="submit">Submit</button>
</form>
<section id="results">
<br>
</section>
<footer>
Created for use with...
</footer>
</div>
</body>
</html>
Код API: app.js
'use strict';
var SwaggerExpress = require('swagger-express-mw');
var SwaggerUi = require('swagger-tools/middleware/swagger-ui');
var app = require('express')();
module.exports = app; // for testing
var config = {
appRoot: __dirname // required config
};
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
// Add swagger-ui (This must be before swaggerExpress.register)
app.use(SwaggerUi(swaggerExpress.runner.swagger));
// Add headers
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Website you wish to allow to connect
res.setHeader('Content-Type', 'application/json');
// Pass to next layer of middleware
next();
});
// install middleware
swaggerExpress.register(app);
var port = process.env.PORT || 10010;
app.listen(port);
if (swaggerExpress.runner.swagger.paths['/ping']) {
console.log('running at: http://127.0.0.1:' + port);
console.log('Ping test: http://127.0.0.1:' + port + '/ping');
}
});
ping.js
'use strict';
var util = require('util');
module.exports = {
ping: ping
};
function ping(req, res) {
// this sends back a JSON response which is a single string
return res.json({ result: 'pong' });
}
swagger.yaml
swagger: "2.0"
info:
version: "0.0.1"
title: My API
# during dev, should point to your local machine
host: xxx.xxx.xxx.xxx:10010
# basePath prefixes all resource paths
basePath: /
#
schemes:
# tip: remove http to make production-grade
- http
- https
# format of bodies a client can send (Content-Type)
consumes:
- application/json
# format of the responses to the client (Accepts)
produces:
- application/json
paths:
/contact:
x-swagger-router-controller: contact
post:
description: Creates a new contact
operationId: create
parameters:
- name: contactemail
in: query
description: Email address of new contact
required: true
type: string
- name: contactname
in: query
description: Name of new contact
required: false
type: string
responses:
"200":
description: Success
schema:
$ref: "#/definitions/CreateContactSuccess"
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
/ping:
# binds a127 app logic to a route
x-swagger-router-controller: ping
get:
description: Returns 'pong' to the caller
# used as the method name of the controller
operationId: ping
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: "#/definitions/PingResponse"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
/swagger:
x-swagger-pipe: swagger_raw
# complex objects have schema definitions
definitions:
CreateContactSuccess:
required:
- contactid
- contactemail
- contactname
properties:
contactid:
type: string
contactemail:
type: string
contactname:
type: string
PingResponse:
required:
- message
properties:
message:
type: string
ErrorResponse:
required:
- message
properties:
message:
type: string
default.yaml
# swagger configuration file
# values in the swagger hash are system configuration for swagger-node
swagger:
fittingsDirs: [ api/fittings ]
defaultPipe: null
swaggerControllerPipe: swagger_controllers # defines the standard processing pipe for controllers
# values defined in the bagpipes key are the bagpipes pipes and fittings definitions
# (see https://github.com/apigee-127/bagpipes)
bagpipes:
_router:
name: swagger_router
mockMode: false
mockControllersDirs: [ api/mocks ]
controllersDirs: [ api/controllers ]
_swagger_validate:
name: swagger_validator
validateResponse: true
# pipe for all swagger-node controllers
swagger_controllers:
- onError: json_error_handler
- cors
- swagger_security
- _swagger_validate
- express_compatibility
- _router
# pipe to serve swagger (endpoint is in swagger.yaml)
swagger_raw:
name: swagger_raw
# any other values in this file are just loaded into the config for application access...