Api stuff

This commit is contained in:
nise.moe 2024-06-11 16:15:17 +02:00
parent 6ebddca877
commit 62bbe14d86
7 changed files with 232 additions and 3 deletions

View File

@ -45,6 +45,7 @@ class ScoreSearchService(
USERS.COUNT_100,
USERS.COUNT_50,
USERS.COUNT_MISS,
USERS.IS_BANNED,
// Scores fields
SCORES.ID,

View File

@ -30,6 +30,18 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" -H "Content-Type: application/json" -d '&#123;"queries"&#58;[&#123;"predicates"&#58;[&#123;"field"&#58;&#123;"name"&#58;"user_rank","type"&#58;"number"&#125;,"operator"&#58;&#123;"operatorType"&#58;"<","acceptsValues"&#58;"any"&#125;,"value"&#58;"50"&#125;,&#123;"field"&#58;&#123;"name"&#58;"ur","type"&#58;"number"&#125;,"operator"&#58;&#123;"operatorType"&#58;"<","acceptsValues"&#58;"any"&#125;,"value"&#58;"120"&#125;&#93;,"logicalOperator"&#58;"AND"&#125;&#93;,"sorting"&#58;&#123;"field"&#58;"user_id","order"&#58;"ASC"&#125;,"page"&#58;1&#125;' https://nise.moe/api/search
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[requestType]="'POST'"
[apiPath]="'search'"
[placeholderValues]="{ body: this.placeholderSearchValue }"
[postFieldValues]="[
{ title: 'body', type: 'string', required: true },
]"
></app-api-try-it>
</div>
</section>
<section>
@ -47,6 +59,18 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" -H "Content-Type: application/json" -d '&#123;"queries"&#58;[&#123;"predicates"&#58;[&#123;"field"&#58;&#123;"name"&#58;"rank","type"&#58;"number"&#125;,"operator"&#58;&#123;"operatorType"&#58;">","acceptsValues"&#58;"any"&#125;,"value"&#58;"10"&#125;,&#123;"field"&#58;&#123;"name"&#58;"username","type"&#58;"string"&#125;,"operator"&#58;&#123;"operatorType"&#58;"=","acceptsValues"&#58;"any"&#125;,"value"&#58;"degenerate"&#125;&#93;,"logicalOperator"&#58;"AND"&#125;&#93;,"sorting"&#58;&#123;"field"&#58;"user_id","order"&#58;"ASC"&#125;,"page"&#58;1&#125;' https://nise.moe/api/search-user
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[requestType]="'POST'"
[apiPath]="'search-user'"
[placeholderValues]="{ body: this.placeholderUserSearchValue }"
[postFieldValues]="[
{ title: 'body', type: 'string', required: true },
]"
></app-api-try-it>
</div>
</section>
<section>
@ -61,6 +85,15 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" https://nise.moe/api/score/3808640439
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[apiPath]="'score/{replay_id}'"
[placeholderValues]="{ replay_id: '3808640439' }"
></app-api-try-it>
</div>
</section>
<section>
@ -76,6 +109,14 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" https://nise.moe/api/score/3808640439/replay
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[apiPath]="'score/{replay_id}/replay'"
[placeholderValues]="{ replay_id: '3808640439' }"
></app-api-try-it>
</div>
</section>
<section>
@ -104,6 +145,19 @@
<app-code-with-copy-button>
curl -X POST -H "X-NISE-API: 20240218" -H "Accept: application/json" -H "Content-Type: application/json" -d '&#123;"userId": 8184689&#125;' https://nise.moe/api/user-details
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[requestType]="'POST'"
[apiPath]="'user-details'"
[placeholderValues]="{ userId: '8184689' }"
[postFieldValues]="[
{ title: 'userId', type: 'number', required: false },
{ title: 'username', type: 'string', required: false }
]"
></app-api-try-it>
</div>
</section>
<section>
@ -137,6 +191,13 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" https://nise.moe/api/suspicious-scores
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[apiPath]="'suspicious-scores'"
></app-api-try-it>
</div>
</section>
<section>
@ -152,6 +213,13 @@
<app-code-with-copy-button>
curl -H "X-NISE-API: 20240218" -H "Accept: application/json" https://nise.moe/api/similar-replays
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[apiPath]="'similar-replays'"
></app-api-try-it>
</div>
</section>
<section>
@ -169,6 +237,18 @@
<app-code-with-copy-button>
curl -X POST -H "X-NISE-API: 20240218" -H "Accept: application/json" -H "Content-Type: application/json" -d '&#123;"page": 1&#125;' https://nise.moe/api/banlist
</app-code-with-copy-button>
<div class="mt-2">
Try it out:
<br>
<app-api-try-it
[requestType]="'POST'"
[apiPath]="'banlist'"
[placeholderValues]="{ page: '1' }"
[postFieldValues]="[
{ title: 'page', type: 'number', required: true },
]"
></app-api-try-it>
</div>
</section>
<section>

View File

@ -6,6 +6,7 @@ import {
CodeWithCopyButtonComponent
} from "../../corelib/components/code-with-copy-button/code-with-copy-button.component";
import {RouterLink} from "@angular/router";
import {ApiTryItComponent} from "../../corelib/components/api-try-it/api-try-it.component";
@Component({
selector: 'app-api',
@ -18,11 +19,15 @@ import {RouterLink} from "@angular/router";
NgForOf,
NgIf,
CodeWithCopyButtonComponent,
RouterLink
RouterLink,
ApiTryItComponent
],
templateUrl: './api.component.html',
styleUrl: './api.component.css'
})
export class ApiComponent {
placeholderSearchValue = "{\"queries\":[{\"predicates\":[{\"field\":{\"name\":\"user_rank\",\"type\":\"number\"},\"operator\":{\"operatorType\":\"<\",\"acceptsValues\":\"any\"},\"value\":\"50\"},{\"field\":{\"name\":\"ur\",\"type\":\"number\"},\"operator\":{\"operatorType\":\"<\",\"acceptsValues\":\"any\"},\"value\":\"120\"}],\"logicalOperator\":\"AND\"}],\"sorting\":{\"field\":\"user_id\",\"order\":\"ASC\"},\"page\":1}";
placeholderUserSearchValue = "{\"queries\":[{\"predicates\":[{\"field\":{\"name\":\"rank\",\"type\":\"number\"},\"operator\":{\"operatorType\":\"<\",\"acceptsValues\":\"any\"},\"value\":\"10\"},{\"field\":{\"name\":\"username\",\"type\":\"string\"},\"operator\":{\"operatorType\":\"=\",\"acceptsValues\":\"any\"},\"value\":\"degenerate\"}],\"logicalOperator\":\"AND\"}],\"sorting\":{\"field\":\"user_id\",\"order\":\"ASC\"},\"page\":1}";
}

View File

@ -11,7 +11,7 @@
<li><a [routerLink]="['/sus']">./suspicious-scores</a></li>
<li><a [routerLink]="['/stolen']">./stolen-replays</a></li>
<li><a [routerLink]="['/search']">./advanced-search</a></li>
<li *ngIf="this.userService.ephemeralUserInfo.showContributions"><a class="link-pink" [routerLink]="['/contribute']">./contribute <3</a></li>
<li *ngIf="this.userService.ephemeralUserInfo.showContributions"><a class="link-pink" [routerLink]="['/contribute']">./contribute </a></li>
</ul>
<form (ngSubmit)="onSubmit()">
<input style="width: 100%" type="text" [(ngModel)]="term" [ngModelOptions]="{standalone: true}" id="nise-osu-username" required minlength="2" maxlength="50" placeholder="Search for users...">
@ -35,5 +35,5 @@
<router-outlet></router-outlet>
<div class="text-center version">
v20240510
v20240511
</div>

View File

@ -0,0 +1,4 @@
pre.response {
max-height: 300px;
overflow: auto;
}

View File

@ -0,0 +1,22 @@
<div>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div *ngFor="let controlName of form.controls | keyvalue">
<label [for]="controlName.key">{{ controlName.key }}:</label>
<input [id]="controlName.key" [formControlName]="controlName.key" type="text">
</div>
<button type="submit" [disabled]="form.invalid">GO!</button>
</form>
<div *ngIf="this.isLoading" class="mt-2">
Loading 'n' stuff...
<app-cute-loading></app-cute-loading>
</div>
<div *ngIf="jsonResponse" style="border: 1px dashed gray; padding: 10px; margin-top: 10px">
<pre class="response">{{ jsonResponse | json }}</pre>
</div>
<div *ngIf="errorMessage" class="alert alert-danger mt-2 text-center">
<p>{{ errorMessage }}</p>
</div>
</div>

View File

@ -0,0 +1,117 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { environment } from '../../../environments/environment';
import {CuteLoadingComponent} from "../cute-loading/cute-loading.component";
@Component({
selector: 'app-api-try-it',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, CuteLoadingComponent],
templateUrl: './api-try-it.component.html',
styleUrls: ['./api-try-it.component.css']
})
export class ApiTryItComponent implements OnInit {
@Input() apiPath: string = '';
@Input() placeholderValues: { [key: string]: string } = {};
@Input() requestType: 'GET' | 'POST' = 'GET';
@Input() postFieldValues: { title: string, type: 'string' | 'number', required: boolean }[] = [];
form: FormGroup;
jsonResponse: any;
errorMessage: string | null = null;
isLoading = false;
constructor(private fb: FormBuilder, private http: HttpClient) {
this.form = this.fb.group({});
}
ngOnInit(): void {
this.createForm();
}
createForm(): void {
const paramRegex = /\{(\w+)\}/g;
let match;
while ((match = paramRegex.exec(this.apiPath)) !== null) {
const placeholderValue = this.placeholderValues[match[1]] || '';
this.form.addControl(match[1], this.fb.control(placeholderValue, Validators.required));
}
if (this.requestType === 'POST') {
this.postFieldValues.forEach(field => {
const validators = [];
if (field.required) {
validators.push(Validators.required);
}
if (field.type === 'number') {
validators.push(Validators.pattern(/^\d+$/));
}
const placeholderValue = this.placeholderValues[field.title] || '';
this.form.addControl(field.title, this.fb.control(placeholderValue, validators));
});
}
}
onSubmit(): void {
this.isLoading = true;
this.jsonResponse = null; // Clear any previous response
let apiUrl = this.apiPath;
Object.keys(this.form.controls).forEach(key => {
apiUrl = apiUrl.replace(`{${key}}`, this.form.get(key)?.value);
});
const url = `${environment.apiUrl}/${apiUrl}`;
const headers = new HttpHeaders({
'X-NISE-API': '20240218',
'Accept': 'application/json',
'Content-Type': 'application/json'
});
if (this.requestType === 'GET') {
this.http.get(url, { headers }).subscribe(
response => {
this.jsonResponse = response;
this.errorMessage = null; // Clear any previous error message
this.isLoading = false;
},
error => {
this.errorMessage = 'There was an error! ' + error.message;
console.error('There was an error!', error);
this.isLoading = false;
}
);
} else if (this.requestType === 'POST') {
const postData: { [key: string]: any } = {};
this.postFieldValues.forEach(field => {
const value = this.form.get(field.title)?.value;
if (value !== null && value !== '') {
postData[field.title] = field.type === 'number' ? Number(value) : value;
}
});
let body: any;
if (postData.hasOwnProperty('body')) {
body = postData['body'];
} else {
body = postData;
}
this.http.post(url, body, { headers }).subscribe(
response => {
this.jsonResponse = response;
this.errorMessage = null; // Clear any previous error message
this.isLoading = false;
},
error => {
this.errorMessage = 'There was an error! ' + error.message;
console.error('There was an error!', error);
this.isLoading = false;
}
);
}
}
}